To display a web page as the part of the application we use android WebView in our application. We’ve covered the basics of WebView here. In this tutorial, we’ll implement a loading ProgressBar with a WebView and also allow bookmarking URLs for later viewing. Let’s get started.
为了将网页显示为应用程序的一部分,我们在应用程序中使用android WebView。 我们已经在这里介绍了WebView的基础知识。 在本教程中,我们将使用WebView实现加载进度条 ,并允许为URL加书签以便以后查看。 让我们开始吧。
Android WebView (Android WebView)
Android WebView
class is an extension of Android’s View class that allows you to display web pages as a part of your activity layout. To load an external page we invoke the method loadUrl(String url)
on the WebView instance and pass in the url of the external page. The WebViewClient contains the following four important methods that are generally overridden.
Android WebView
类是Android View类的扩展,它允许您将网页显示为活动布局的一部分。 要加载外部页面,我们在WebView实例上调用方法loadUrl(String url)
并传入外部页面的url。 WebViewClient包含以下四个通常被覆盖的重要方法。
onPageStarted
: As the name suggests, this method gets invoked when the url loading starts.onPageStarted
:顾名思义,此方法在开始加载URL时被调用。shouldOverrideUrlLoading
: This method is called whenever an internal link from an already loaded page is clicked. For API>24shouldOverrideUrlLoading(WebView view, String url)
is deprecated, useshouldOverrideUrlLoading(WebView view, WebResourceRequest request)
instead.shouldOverrideUrlLoading
:每当单击来自已加载页面的内部链接时,都会调用此方法。 对于API> 24shouldOverrideUrlLoading(WebView view, String url)
不建议使用shouldOverrideUrlLoading(WebView view, WebResourceRequest request)
shouldOverrideUrlLoading(WebView view, String url)
,请改用shouldOverrideUrlLoading(WebView view, WebResourceRequest request)
。onPageFinished
: When the url is loaded completely and successfully, this gets invokedonPageFinished
:当URL完全成功加载时,将调用此方法onReceivedError
: When the url isn’t loaded, this method gets invoked.onReceivedError
:未加载网址时,将调用此方法。
To enable zoom controls on the webview we can invoke the following methods on the webView instance.
为了在webview上启用缩放控件,我们可以在webView实例上调用以下方法。
webView.getSettings().setSupportZoom(true);
webView.getSettings().setBuiltInZoomControls(true); // allow pinch to zooom
webView.getSettings().setDisplayZoomControls(false); // disable the default zoom controls on the page
Let’s create an application that loads a web page whilst showing the ProgressBar. We’ll add a functionality that lets us bookmark a URL and save it in our SharedPreferences for later viewing.
让我们创建一个在显示ProgressBar的同时加载网页的应用程序。 我们将添加一项功能,使我们可以为URL添加书签并将其保存在SharedPreferences中,以供以后查看。
具有书签项目结构的Android WebView (Android WebView with Bookmark Project Structure)
We’ve selected the Activity type as Navigation Drawer.
我们已将“活动”类型选择为“ 导航抽屉” 。
Note: If you’ve updated your build tools to API 26 and are experiencing an error : “Failed to resolve com.android.support:appcompat-v7:26.0.1
“, you need to add Google’s Maven Repository in the build.gradle
file as shown below:
注意:如果您已经将构建工具更新为API 26,并且遇到错误:“无法解析com.android.support:appcompat-v7:26.0.1
”,则需要在build.gradle
添加Google的Maven存储库文件如下图所示:
apply plugin: 'com.android.application'
allprojects {
repositories {
jcenter()
maven {
url "https://maven.google.com"
}
}
}
android {
compileSdkVersion 26
buildToolsVersion "26.0.1"
defaultConfig {
applicationId "com.journaldev.webviewwithbookmarks"
minSdkVersion 16
targetSdkVersion 26
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.android.support:appcompat-v7:26.0.1'
compile 'com.android.support:design:26.0.1'
compile 'com.google.code.gson:gson:2.7'
compile 'com.android.support.constraint:constraint-layout:1.0.2'
testCompile 'junit:junit:4.12'
}
Note: The Gson library dependency for saving bookmarked urls in Shared Preferences is also added above.
注意:上面还添加了用于在“ 共享首选项”中保存书签网址的Gson库依赖项。
Android WebView书签代码 (Android WebView Bookmarks Code)
The code of the activity_main.xml
layout is given below:
下面给出了activity_main.xml
布局的代码:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout xmlns:android="https://schemas.android.com/apk/res/android"
xmlns:app="https://schemas.android.com/apk/res-auto"
xmlns:tools="https://schemas.android.com/tools"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:openDrawer="start">
<include
layout="@layout/app_bar_main"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<android.support.design.widget.NavigationView
android:id="@+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:headerLayout="@layout/nav_header_main"
app:menu="@menu/activity_main_drawer" />
</android.support.v4.widget.DrawerLayout>
The code for the app_bar_main.xml
layout is given below:
下面给出了app_bar_main.xml
布局的代码:
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="https://schemas.android.com/apk/res/android"
xmlns:app="https://schemas.android.com/apk/res-auto"
xmlns:tools="https://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.journaldev.webviewwithbookmarks.MainActivity">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="@style/AppTheme.PopupOverlay" />
</android.support.design.widget.AppBarLayout>
<include layout="@layout/content_main" />
</android.support.design.widget.CoordinatorLayout>
The layout for the content_main.xml
is given below. It contains a Button that’ll be used to launch another activity.
下面给出了content_main.xml
的布局。 它包含一个将用于启动另一个活动的按钮。
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="https://schemas.android.com/apk/res/android"
xmlns:app="https://schemas.android.com/apk/res-auto"
xmlns:tools="https://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:context="com.journaldev.webviewwithbookmarks.MainActivity"
tools:showIn="@layout/app_bar_main">
<Button
android:id="@+id/btnLaunchWebsite"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="LAUNCH WEBSITE"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
The code for the MainActivity.java is given below:
MainActivity.java的代码如下:
package com.journaldev.webviewwithbookmarks;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.support.design.widget.NavigationView;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Button;
public class MainActivity extends AppCompatActivity
implements NavigationView.OnNavigationItemSelectedListener {
Button button;
NavigationView navigationView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
DrawerLayout drawer = findViewById(R.id.drawer_layout);
button = findViewById(R.id.btnLaunchWebsite);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
gotoBrowserActivity();
}
});
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawer.addDrawerListener(toggle);
toggle.syncState();
navigationView = findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(this);
}
@Override
public void onBackPressed() {
DrawerLayout drawer = findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else {
super.onBackPressed();
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
public boolean onNavigationItemSelected(MenuItem item) {
// Handle navigation view item clicks here.
int id = item.getItemId();
if (id == R.id.nav_home) {
navigationView.getMenu().getItem(0).setChecked(false);
} else if (id == R.id.nav_bookmark) {
navigationView.getMenu().getItem(1).setChecked(false);
startActivity(new Intent(this, BookmarkActivity.class));
}
DrawerLayout drawer = findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
return true;
}
private void gotoBrowserActivity() {
startActivity(new Intent(this, BrowserActivity.class));
}
}
In the above code we’ve defined two menu options(the file resides inside the menu folder as activity_main_drawer.xml
) inside the NavigationDrawer.
在上面的代码中,我们在NavigationDrawer中定义了两个菜单选项(文件位于菜单文件夹中,名称为activity_main_drawer.xml
)。
Clicking the Button in the MainActivity.java
would launch the BrowserActivity.java
and clicking the Bookmark menu button would launch the BookmarkActivity.java
that we’ll see shortly.
单击MainActivity.java
的Button将启动BrowserActivity.java
,单击Bookmark菜单按钮将启动BookmarkActivity.java
,我们将很快看到。
Add the following permission to access internet in your AndroidManifest.xml
.
在AndroidManifest.xml
添加以下访问互联网的权限。
<uses-permission android:name="android.permission.INTERNET"/>
The code for the activity_browser.xml
is given below.
下面给出了activity_browser.xml
的代码。
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="https://schemas.android.com/apk/res/android"
xmlns:app="https://schemas.android.com/apk/res-auto"
android:id="@+id/main_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/white"
android:fitsSystemWindows="true">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="@style/AppTheme.PopupOverlay" />
</android.support.design.widget.AppBarLayout>
<android.support.v4.widget.NestedScrollView xmlns:android="https://schemas.android.com/apk/res/android"
xmlns:app="https://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fadeScrollbars="false"
android:scrollbarFadeDuration="0"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<WebView
android:id="@+id/webView"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</android.support.v4.widget.NestedScrollView>
<ProgressBar
android:id="@+id/progressBar"
style="@style/Widget.AppCompat.ProgressBar.Horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="-7dp"
android:indeterminate="true"
android:visibility="gone"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
</android.support.design.widget.CoordinatorLayout>
The code for the BrowserActivity.java
is given below:
下面给出了BrowserActivity.java
的代码:
package com.journaldev.webviewwithbookmarks;
import android.content.Context;
import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.support.design.widget.CoordinatorLayout;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.webkit.WebResourceError;
import android.webkit.WebResourceRequest;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.ProgressBar;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import java.util.ArrayList;
public class BrowserActivity extends AppCompatActivity {
public static final String PREFERENCES = "PREFERENCES_NAME";
public static final String WEB_LINKS = "links";
public static final String WEB_TITLE = "title";
WebView webView;
private ProgressBar progressBar;
String current_page_url = "https://www.wikipedia.com";
CoordinatorLayout coordinatorLayout;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_browser);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setTitle("");
toolbar.setNavigationIcon(R.drawable.ic_arrow_back);
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
onBackPressed();
}
});
if (getIntent().getExtras() != null) {
current_page_url = getIntent().getStringExtra("url");
}
webView = findViewById(R.id.webView);
progressBar = findViewById(R.id.progressBar);
webView.loadUrl(current_page_url);
initWebView();
coordinatorLayout = findViewById(R.id.main_content);
}
private void initWebView() {
webView.setWebViewClient(new WebViewClient() {
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
super.onPageStarted(view, url, favicon);
progressBar.setVisibility(View.VISIBLE);
current_page_url = url;
invalidateOptionsMenu();
}
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
webView.loadUrl(url);
return true;
}
@Override
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
webView.loadUrl(request.getUrl().toString());
}
return true;
}
@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
progressBar.setVisibility(View.GONE);
invalidateOptionsMenu();
}
@Override
public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
super.onReceivedError(view, request, error);
progressBar.setVisibility(View.GONE);
invalidateOptionsMenu();
}
});
webView.getSettings().setLoadWithOverviewMode(true);
webView.getSettings().setUseWideViewPort(true);
webView.clearCache(true);
webView.clearHistory();
webView.getSettings().setJavaScriptEnabled(true);
webView.setHorizontalScrollBarEnabled(true);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.browser, menu);
SharedPreferences sharedPreferences = getSharedPreferences(PREFERENCES, Context.MODE_PRIVATE);
String links = sharedPreferences.getString(WEB_LINKS, null);
if (links != null) {
Gson gson = new Gson();
ArrayList<String> linkList = gson.fromJson(links, new TypeToken<ArrayList<String>>() {
}.getType());
if (linkList.contains(current_page_url)) {
menu.getItem(0).setIcon(R.drawable.ic_bookmark_black_24dp);
} else {
menu.getItem(0).setIcon(R.drawable.ic_bookmark_border_black_24dp);
}
} else {
menu.getItem(0).setIcon(R.drawable.ic_bookmark_border_black_24dp);
}
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == R.id.action_bookmark) {
String message;
SharedPreferences sharedPreferences = getSharedPreferences(PREFERENCES, Context.MODE_PRIVATE);
String jsonLink = sharedPreferences.getString(WEB_LINKS, null);
String jsonTitle = sharedPreferences.getString(WEB_TITLE, null);
if (jsonLink != null && jsonTitle != null) {
Gson gson = new Gson();
ArrayList<String> linkList = gson.fromJson(jsonLink, new TypeToken<ArrayList<String>>() {
}.getType());
ArrayList<String> titleList = gson.fromJson(jsonTitle, new TypeToken<ArrayList<String>>() {
}.getType());
if (linkList.contains(current_page_url)) {
linkList.remove(current_page_url);
titleList.remove(webView.getTitle().trim());
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putString(WEB_LINKS, new Gson().toJson(linkList));
editor.putString(WEB_TITLE, new Gson().toJson(titleList));
editor.apply();
message = "Bookmark Removed";
} else {
linkList.add(current_page_url);
titleList.add(webView.getTitle().trim());
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putString(WEB_LINKS, new Gson().toJson(linkList));
editor.putString(WEB_TITLE, new Gson().toJson(titleList));
editor.apply();
message = "Bookmarked";
}
} else {
ArrayList<String> linkList = new ArrayList<>();
ArrayList<String> titleList = new ArrayList<>();
linkList.add(current_page_url);
titleList.add(webView.getTitle());
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putString(WEB_LINKS, new Gson().toJson(linkList));
editor.putString(WEB_TITLE, new Gson().toJson(titleList));
editor.apply();
message = "Bookmarked";
}
Snackbar snackbar = Snackbar.make(coordinatorLayout, message, Snackbar.LENGTH_LONG);
snackbar.show();
invalidateOptionsMenu();
}
return super.onOptionsItemSelected(item);
}
@Override
public void onBackPressed() {
if (webView.canGoBack()) {
webView.goBack();
} else {
super.onBackPressed();
}
}
}
In the above code, we load the url https://www.wikipedia.com
in the WebView.
在上面的代码中,我们在WebView中加载URL https://www.wikipedia.com
。
We display and hide the ProgressBar when the url is loading and completed respectively.
分别在加载和完成URL时显示和隐藏ProgressBar。
The menu is inflated from the browser.xml
file as shown below.
菜单从browser.xml
文件browser.xml
,如下所示。
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="https://schemas.android.com/apk/res/android"
xmlns:app="https://schemas.android.com/apk/res-auto">
<item
android:id="@+id/action_bookmark"
android:icon="@drawable/ic_bookmark_black_24dp"
android:orderInCategory="100"
android:title="BOOKMARK"
app:showAsAction="always" />
</menu>
In the onCreateOptionsMenu()
we check if the current_page_url already exists in our SharedPreferences or not. Depending on the outcome, we show the relevant bookmark menu icon.
在onCreateOptionsMenu()
我们检查current_page_url是否已存在于我们的SharedPreferences中。 根据结果,我们显示相关的书签菜单图标。
In the onOptionsItemSelected()
we store or remove the url from the SharedPreferences depending on whether it exists or not.
在onOptionsItemSelected()
我们根据URL是否存在来存储或从SharedPreferences中删除该URL。
The SharedPreferences stores the ArrayList of links and the respective web page titles, in the form of Gson strings that’ll be eventually displayed in the BookmarkActivity.java
which we’ll discuss below.
SharedPreferences以Gson字符串的形式存储链接的ArrayList和相应的网页标题,这些字符串最终将显示在BookmarkActivity.java
,我们将在下面进行讨论。
invalidateOptionsMenu()
is used to redraw the menu in the Toolbar.
invalidateOptionsMenu()
用于在工具栏中重新绘制菜单。
onBackPressed()
is used to navigate back through the web page if the user had clicked any of the internal links in the WebView by checking and returning using canGoBack()
and goBack()
.
如果用户通过使用canGoBack()
和goBack()
进行检查并返回来canGoBack()
WebView中的任何内部链接,则使用onBackPressed()
来浏览网页。
The code for activity_bookmark.xml
is given below.
下面给出了activity_bookmark.xml
的代码。
<RelativeLayout xmlns:android="https://schemas.android.com/apk/res/android"
xmlns:app="https://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:layout_alignParentTop="true"
android:background="?attr/colorPrimary"
app:popupTheme="@style/AppTheme.PopupOverlay" />
<android.support.v4.widget.SwipeRefreshLayout
android:id="@+id/swipeToRefresh"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/toolbar"
android:layout_margin="@dimen/fab_margin">
<ListView
android:id="@+id/listView"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</android.support.v4.widget.SwipeRefreshLayout>
<LinearLayout
android:id="@+id/emptyList"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:gravity="center"
android:orientation="vertical"
android:visibility="gone">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:text="WHOOPS"
android:textColor="#212121"
android:textSize="20sp"
android:textStyle="bold" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:text="There are no bookmarks at the moment"
android:textColor="#212121" />
</LinearLayout>
</RelativeLayout>
The code for the BookmarkActivity.java
is given below.
下面给出了BookmarkActivity.java
的代码。
package com.journaldev.webviewwithbookmarks;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.widget.AdapterView;
import android.widget.LinearLayout;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import static com.journaldev.webviewwithbookmarks.BrowserActivity.PREFERENCES;
import static com.journaldev.webviewwithbookmarks.BrowserActivity.WEB_LINKS;
import static com.journaldev.webviewwithbookmarks.BrowserActivity.WEB_TITLE;
public class BookmarkActivity extends AppCompatActivity {
ArrayList<HashMap<String, String>> listRowData;
public static String TAG_TITLE = "title";
public static String TAG_LINK = "link";
ListView listView;
ListAdapter adapter;
LinearLayout linearLayout;
SwipeRefreshLayout mSwipeRefreshLayout;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_bookmark);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setTitle("BOOKMARKS");
toolbar.setNavigationIcon(R.drawable.ic_arrow_back);
toolbar.setTitleTextColor(getResources().getColor(android.R.color.white));
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
onBackPressed();
}
});
listView = findViewById(R.id.listView);
linearLayout = findViewById(R.id.emptyList);
mSwipeRefreshLayout = findViewById(R.id.swipeToRefresh);
mSwipeRefreshLayout.setColorSchemeResources(R.color.colorAccent);
mSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
new LoadBookmarks().execute();
}
});
new LoadBookmarks().execute();
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
Object o = listView.getAdapter().getItem(position);
if (o instanceof Map) {
Map map = (Map) o;
Intent in = new Intent(BookmarkActivity.this, BrowserActivity.class);
in.putExtra("url", String.valueOf(map.get(TAG_LINK)));
startActivity(in);
}
}
});
listView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
@Override
public boolean onItemLongClick(AdapterView<?> adapterView, View view, int i, long l) {
Object o = listView.getAdapter().getItem(i);
if (o instanceof Map) {
Map map = (Map) o;
deleteBookmark(String.valueOf(map.get(TAG_TITLE)), String.valueOf(map.get(TAG_LINK)));
}
return true;
}
});
}
private class LoadBookmarks extends AsyncTask<String, String, String> {
@Override
protected void onPreExecute() {
super.onPreExecute();
}
@Override
protected String doInBackground(String... args) {
// updating UI from Background Thread
runOnUiThread(new Runnable() {
public void run() {
SharedPreferences sharedPreferences = getSharedPreferences(PREFERENCES, Context.MODE_PRIVATE);
String jsonLink = sharedPreferences.getString(WEB_LINKS, null);
String jsonTitle = sharedPreferences.getString(WEB_TITLE, null);
listRowData = new ArrayList<>();
if (jsonLink != null && jsonTitle != null) {
Gson gson = new Gson();
ArrayList<String> linkArray = gson.fromJson(jsonLink, new TypeToken<ArrayList<String>>() {
}.getType());
ArrayList<String> titleArray = gson.fromJson(jsonTitle, new TypeToken<ArrayList<String>>() {
}.getType());
for (int i = 0; i < linkArray.size(); i++) {
HashMap<String, String> map = new HashMap<>();
if (titleArray.get(i).length() == 0)
map.put(TAG_TITLE, "Bookmark " + (i + 1));
else
map.put(TAG_TITLE, titleArray.get(i));
map.put(TAG_LINK, linkArray.get(i));
listRowData.add(map);
}
adapter = new SimpleAdapter(BookmarkActivity.this,
listRowData, R.layout.bookmark_list_row,
new String[]{TAG_TITLE, TAG_LINK},
new int[]{R.id.title, R.id.link});
listView.setAdapter(adapter);
}
linearLayout.setVisibility(View.VISIBLE);
listView.setEmptyView(linearLayout);
}
});
return null;
}
protected void onPostExecute(String args) {
mSwipeRefreshLayout.setRefreshing(false);
}
}
private void deleteBookmark(final String title, final String link) {
new AlertDialog.Builder(this)
.setTitle("DELETE")
.setMessage("Confirm that you want to delete this bookmark?")
.setPositiveButton("YES", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
SharedPreferences sharedPreferences = getSharedPreferences(PREFERENCES, Context.MODE_PRIVATE);
String jsonLink = sharedPreferences.getString(WEB_LINKS, null);
String jsonTitle = sharedPreferences.getString(WEB_TITLE, null);
if (jsonLink != null && jsonTitle != null) {
Gson gson = new Gson();
ArrayList<String> linkArray = gson.fromJson(jsonLink, new TypeToken<ArrayList<String>>() {
}.getType());
ArrayList<String> titleArray = gson.fromJson(jsonTitle, new TypeToken<ArrayList<String>>() {
}.getType());
linkArray.remove(link);
titleArray.remove(title);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putString(WEB_LINKS, new Gson().toJson(linkArray));
editor.putString(WEB_TITLE, new Gson().toJson(titleArray));
editor.apply();
new LoadBookmarks().execute();
}
dialogInterface.dismiss();
}
}).setNegativeButton("NO", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
dialogInterface.dismiss();
}
}).show();
}
}
In the above code we deserialise the strings from SharedPreferences
using Gson and convert them into the respective links and titles ArrayList of Strings inside the AsyncTask LoadBookmarks.
在上面的代码中,我们使用Gson反序列化了SharedPreferences
的字符串,并将它们转换为AsyncTask LoadBookmarks内部的相应链接和标题为ArrayList of Strings。
SimpleAdapter is a built-in adapter for the ListView. Its useful to map static data to views defined in an XML file.
SimpleAdapter是ListView的内置适配器。 将静态数据映射到XML文件中定义的视图很有用。
The layout for the ListView rows is given below:
ListView行的布局如下所示:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="https://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
<TextView
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="1"
android:paddingBottom="2dp"
android:paddingTop="4dp"
android:textColor="#000"
android:textSize="16sp" />
<TextView
android:id="@+id/link"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="1"
android:layout_below="@+id/title"
android:paddingBottom="4dp"
android:paddingTop="2dp"
android:textSize="14sp" />
</RelativeLayout>
setOnItemLongClickListener()
is invoked to long press to delete a bookmark. Returning a false
in it would call setOnItemClickListener()
at the same time too, hence its recommended to return true
.
调用setOnItemLongClickListener()
可以长按删除书签。 在其中返回false
也会同时调用setOnItemClickListener()
,因此建议返回true
。
The output that the application gives is shown below.
该应用程序给出的输出如下所示。
This brings an end to this tutorial. You can download the final Android WebViewWithBookmarks Project from the link below.
本教程到此结束。 您可以从下面的链接下载最终的Android WebViewWithBookmarks项目 。
References: WebView, Simple Adapter
翻译自: https://www.journaldev.com/15729/android-webview-bookmarks