Android

Create a WebView in Android Studio: ProgressBar + Swipe to Refresh + Custom Error Page on Network Failure

Estimated reading time: 7 minutes

What is a WebView?

A WebView is an embeddable browser that helps a native application, such as Android, to display web content. If you are writing an application that needs to deliver a web content or show a web page as a part of a client application, you can do it smoothly and efficiently using WebView.

According to the Android Studio documentation, the WebView class is an extension of Android’s View class that allows you to display web pages as a part of your activity layout. It does not include any features of a fully developed web browser, such as navigation controls or an address bar. All that WebView does, by default, is show a web page.

In this article, we shall see how to:

  1. Use Android’s native webView wrapper to load site’s url
  2. Add and dismiss progressBar
  3. Utilize the Swipe to refresh feature of Android’s webView.
  4. Add a custom error page on network failure.

Let us begin …

Step 1: Open up your Android Studio and select Empty Activity

Android Studio Project Setup

Step 2: Add the following dependency in build.gradle file inside the app folder

implementation 'com.google.android.material:material:1.0.0'

Step 3: Sync project with gradle files

Sync Project With Gradle Files

Step 4: Add the following code to your activity_main.xml file in res->layout folder

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

   <androidx.swiperefreshlayout.widget.SwipeRefreshLayout
       android:id="@+id/swipe"
       android:layout_width="match_parent"
       android:layout_height="match_parent"
       tools:layout_behavior="@string/appbar_scrolling_view_behavior">



       <WebView
           android:id="@+id/web"
           android:layout_width="match_parent"
           android:layout_height="match_parent"/>


   </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>


    <ProgressBar
        android:id="@+id/progress"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_centerVertical="true"
        android:layout_centerHorizontal="true"
        style="?android:attr/progressBarStyle"
        />

</RelativeLayout>

Step: 5 We will go to our MainActivity.java file and add the code to display the WebView

public class MainActivity extends AppCompatActivity {

    WebView webView;
    ProgressBar progressBar;
    SwipeRefreshLayout swipeRefreshLayout;

    @SuppressLint("SetJavaScriptEnabled")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        getSupportActionBar().hide();

        webView = findViewById(R.id.web);
        progressBar = findViewById(R.id.progress);
        swipeRefreshLayout = findViewById(R.id.swipe);


        webView.getSettings().setJavaScriptEnabled(true);
        webView.getSettings().setSupportZoom(false);
        webView.getSettings().setDomStorageEnabled(true);
        webView.setWebViewClient(new myWebViewclient());
        webView.loadUrl("http://codeflarelimited.com");
}
}

Here we setting up our basic WebView and just passing the url we want to wrap. Notice also that we have initialized the SwipeRefreshLayout, and that’s all we are doing here. We need to make it show and dismiss it when the page is fully loaded.

So we add the following code:

 swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
            @Override
            public void onRefresh() {
                swipeRefreshLayout.setRefreshing(true);
                new Handler().postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        swipeRefreshLayout.setRefreshing(false);
                        webView.loadUrl("http://codeflarelimited.com");
                    }
                },  3000);
            }
        });

        swipeRefreshLayout.setColorSchemeColors(
                getResources().getColor(android.R.color.holo_blue_bright),
                getResources().getColor(android.R.color.holo_orange_dark),
                getResources().getColor(android.R.color.holo_green_dark),
                getResources().getColor(android.R.color.holo_red_dark)
        );

    }

Notice we are also using WebViewClient. The WebViewClient allows us to handle navigation inside the WebView and to also handle the various events generated by the WebView. It is also in this WebViewClient block that we want to check for errors, network errors, SSL errors, etc.

We want to be able to handle errors in a nice and responsible way. So we’ll add the following code:

public class myWebViewclient extends WebViewClient{

        @Override
        public boolean shouldOverrideUrlLoading(WebView view, String url) {
            view.loadUrl(url);
            return true;
        }

        @Override
        public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
            Toast.makeText(getApplicationContext(), "No internet connection", Toast.LENGTH_LONG).show();
            webView.loadUrl("file:///android_asset/lost.html");
        }

        @Override
        public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
            super.onReceivedSslError(view, handler, error);
            handler.cancel();
        }

        @Override
        public void onPageStarted(WebView view, String url, Bitmap favicon) {
            super.onPageStarted(view, url, favicon);
            progressBar.setVisibility(View.VISIBLE);
        }

        @Override
        public void onPageFinished(WebView view, String url) {
            super.onPageFinished(view, url);
            progressBar.setVisibility(View.GONE);
        }
    }

Now, let us explain what’s happening here. First we’re handling navigation here within the WebVeiw because of this line of code:

 public boolean shouldOverrideUrlLoading(WebView view, String url) {
            view.loadUrl(url);
            return true;
        }

This ensures that whatever url that is loaded in the WebView opens up in the WebVeiw and does not navigate away or open up chrome or other web browser.

Next, we have the onReceivedError method. This is where we check for error, and to handle that we have created an offline html file that will load when the app encounters a network failure.

Don’t forget to handle Back Navigation for the WebView!

The default behaviour of webView applications, especially in Android, is that once you press the back button it closes the application. But what if we have visited several pages and we want to go back to the previous page?

So we need to handle the back navigation and just say if the webView has previous pages and canGoBack(), let it just goBack(). We’ll add the following code as well:

 @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {

        if ((keyCode == KeyEvent.KEYCODE_BACK) && webView.canGoBack()) {
            webView.goBack();
            return true;
        }
        return super.onKeyDown(keyCode, event);
    }

Here’s the full code for the MainActvity.java file:

import androidx.appcompat.app.AppCompatActivity;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;

import android.annotation.SuppressLint;
import android.graphics.Bitmap;
import android.net.http.SslError;
import android.os.Bundle;
import android.os.Handler;
import android.view.KeyEvent;
import android.view.View;
import android.webkit.SslErrorHandler;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.ProgressBar;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

    WebView webView;
    ProgressBar progressBar;
    SwipeRefreshLayout swipeRefreshLayout;

    @SuppressLint("SetJavaScriptEnabled")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        getSupportActionBar().hide();

        webView = findViewById(R.id.web);
        progressBar = findViewById(R.id.progress);
        swipeRefreshLayout = findViewById(R.id.swipe);


        webView.getSettings().setJavaScriptEnabled(true);
        webView.getSettings().setSupportZoom(false);
        webView.getSettings().setDomStorageEnabled(true);
        webView.setWebViewClient(new myWebViewclient());
        webView.loadUrl("http://codeflarelimited.com");

        swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
            @Override
            public void onRefresh() {
                swipeRefreshLayout.setRefreshing(true);
                new Handler().postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        swipeRefreshLayout.setRefreshing(false);
                        webView.loadUrl("http://codeflarelimited.com");
                    }
                },  3000);
            }
        });

        swipeRefreshLayout.setColorSchemeColors(
                getResources().getColor(android.R.color.holo_blue_bright),
                getResources().getColor(android.R.color.holo_orange_dark),
                getResources().getColor(android.R.color.holo_green_dark),
                getResources().getColor(android.R.color.holo_red_dark)
        );

    }


    public class myWebViewclient extends WebViewClient{

        @Override
        public boolean shouldOverrideUrlLoading(WebView view, String url) {
            view.loadUrl(url);
            return true;
        }

        @Override
        public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
            Toast.makeText(getApplicationContext(), "No internet connection", Toast.LENGTH_LONG).show();
            webView.loadUrl("file:///android_asset/lost.html");
        }

        @Override
        public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
            super.onReceivedSslError(view, handler, error);
            handler.cancel();
        }

        @Override
        public void onPageStarted(WebView view, String url, Bitmap favicon) {
            super.onPageStarted(view, url, favicon);
            progressBar.setVisibility(View.VISIBLE);
        }

        @Override
        public void onPageFinished(WebView view, String url) {
            super.onPageFinished(view, url);
            progressBar.setVisibility(View.GONE);
        }
    }


    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {

        if ((keyCode == KeyEvent.KEYCODE_BACK) && webView.canGoBack()) {
            webView.goBack();
            return true;
        }
        return super.onKeyDown(keyCode, event);
    }
}

To Create the lost.html file for the WebView

First, we need to create an assets folder like so:

Create Assets Folder in Android Studio

Next, we create an image folder right inside the assets folder and just put our image there. This image will portray a network failure. I have decided to call my own gone.png. Feel free to use any image of your choice:

Network failure

Add the following code to the lost.html file

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Connection Failed</title>
    <style>
  body {
  display: inline-block;
  background: #00AFF9 url('img/gone.png') center/cover no-repeat;
  height: 100vh;
  margin: 0;
  color: white;
}

h1 {
  margin: .8em 3rem;
  font: 4em Roboto;
}
p {
  display: inline-block;
  margin: .2em 3rem;
  font: 2em Roboto;
}
 </style>
</head>
<body>
<center>
    <h2 style="text-align:center;padding:5px;color:#d9534f">The network failed</h2>
    <h2 style="text-align:center;padding:5px;color:#d9534f">Check your network connection and swipe to refresh </h2>
</center>

</body>
</html>

See 7 Reasons Why You Should Learn Software Development

Wait, before you run!

You need to add instructions for internet connection in your AndroidManifest.xml file otherwise the webView won’t show. This way we can request permission to use the internet

AndroidManifest.xml

 <uses-permission android:name="android.permission.INTERNET"/>

Congrats! We’re good to go.

Watch Video instead.

Also get Github repo link in video description

Author

Share
Published by
codeflare

Recent Posts

Observer Pattern in JavaScript: Implementing Custom Event Systems

Introduction The Observer Pattern is a design pattern used to manage and notify multiple objects…

4 weeks ago

Memory Management in JavaScript

Memory management is like housekeeping for your program—it ensures that your application runs smoothly without…

1 month ago

TypeScript vs JavaScript: When to Use TypeScript

JavaScript has been a developer’s best friend for years, powering everything from simple websites to…

1 month ago

Ethics in Web Development: Designing for Inclusivity and Privacy

In the digital age, web development plays a crucial role in shaping how individuals interact…

1 month ago

Augmented Reality (AR) in Web Development Augmented Reality (AR) is reshaping the way users interact…

1 month ago

Node.js Streams: Handling Large Data Efficiently

Introduction Handling large amounts of data efficiently can be a challenge for developers, especially when…

1 month ago