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
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.
onPageStarted
: As the name suggests, this method gets invoked when the url loading starts.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.onPageFinished
: When the url is loaded completely and successfully, this gets invokedonReceivedError
: When the url isn’t loaded, this method gets invoked.
To enable zoom controls on the webview we can invoke the following methods on the webView instance.
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.
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:
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.
Android WebView Bookmarks Code
The code of the activity_main.xml
layout is given below:
<?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:
<?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.
<?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:
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.
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.
Add the following permission to access internet in your AndroidManifest.xml
.
<uses-permission android:name="android.permission.INTERNET"/>
The code for the activity_browser.xml
is given below.
<?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:
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.
We display and hide the ProgressBar when the url is loading and completed respectively.
The menu is inflated from the browser.xml
file as shown below.
<?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.
In the onOptionsItemSelected()
we store or remove the url from the SharedPreferences depending on whether it exists or not.
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.
invalidateOptionsMenu()
is used to redraw the menu in the Toolbar.
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()
.
The code for activity_bookmark.xml
is given below.
<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.
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.
SimpleAdapter is a built-in adapter for the ListView. Its useful to map static data to views defined in an XML file.
The layout for the ListView rows is given below:
<?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
.
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.
References: WebView, Simple Adapter