[Java for Android App Development] bassie1995:
Hello everyone,

For a while now, I had been trying to figure out how to download and display a web page's HTML file in a WebView. Why, you ask? Well, because this app is probably going to be used offline. More importantly, it is just another thing that you can learn to do and have in your skillset.

A long time passed from my initial Googling efforts, and I forgot about this for a bit. After a couple of weeks, I picked this up again and got it to work correctly.

Since so many different tutorials and explanations exist, I wanted to give a clear and detailed explanation, as well as try to help anyone who attempts to implement this.

So, here we go!

Step 1:

Of course, you need to have specified a button that executes an action.

I chose to have an ActionBar item that checks whether or not the SD card is accessible to your app. It also calls the ASyncTask that downloads the file.

To do this, I used:

case R.id.save: // Save item
if (Environment.getExternalStorageState().equals(
Environment.MEDIA_MOUNTED)) {

// execute this when the downloader must be fired
DownloadFile downloadFile = new DownloadFile();
downloadFile.execute(downloadUrl);

} else {
Toast.makeText(this, "Can't write to internal storage",
Toast.LENGTH_LONG).show();
}

This checks whether the internal SD card is mounted. If it is, it starts a new download, and gets the file at the webpage with the URL downloadUrl.

If the SD card cannot be accessed, it will show so in a Toast.

Step 2:

For part 2, we will set up the actual download of the file. This is done by an ASyncTask. You can, should you want to, show a progress indicator. However, since I only download small files, I have chosen not to do so.

To download the file:

private class DownloadFile extends AsyncTask<String, Integer, String> {
[MENTION=439709]override[/MENTION]
protected String doInBackground(String... sUrl) {
try {

URL url = new URL(downloadUrl);
URLConnection connection = url.openConnection();
connection.connect();

// download the file
InputStream input = new BufferedInputStream(url.openStream());
OutputStream output = new FileOutputStream(Environment
.getExternalStorageDirectory().getPath()
+ "/data/"
+ getPackageName() + "/webpage.html");

byte data[] = new byte[1024];
int count;
try {
while ((count = input.read(data)) != -1)
output.write(data, 0, count);
} catch (IOException e) {
e.printStackTrace();
}

output.flush();
output.close();
input.close();

Toast.makeText(MyWebView.this, "File downloaded", Toast.LENGTH_SHORT).show();

} catch (IOException ioe) {
ioe.printStackTrace();
}
return null;
}
}

So, what do we see here?

Firstly, make a new ASyncTask class. This has a number of standard methods, including one that executes everything in it in a separate background thread: doInBackground.

Now, you want to open a new connection to the site's server, with the downloadUrl, and connect to it. This is easily done with a standard class called URLConnection.

To download and write the file to a specific location on the SD, open a new InputStream. This will download the file from the downloadURL.

Once you have done that, make a new OutputStream to open a connection to the internal storage. In my case, I am writing to what would be /sdcard/data/<mypackagename>/webpage.html, because every new download overwrites the file that was downloaded last.

To actually write the file to the SD, byte by byte, create a new bit array and a counter. As long as there's still data to be read from the file, write the data.

As the last step here, you want to clean and close your in- and output streams, etc. Just do this with the standard commands.

Then show the user a short Toast, to let them know the file has been downloaded correctly.

Should an IOException occur, I print the stack trace.

It would be good to notify the user of the error, though you shouldn't do it in an obtrusive way.

Step 3:

Now, we're almost done. I know you want to know what else is to be done, since the hard parts have been coded already.

This is true, but placement is very important. You want to have the ASyncTask placed correctly in your code.

So, where does it go? Just put it at the bottom of your original class. Subclasses of ASyncTask are usually inside the main Activity class. This ensures you can still easily modify the UI thread (foreground thread, which we use for the Toasts).

Everything should now work, just code a nice little Button (or something else) that triggers the download.

Step 4:

Now, we want to display this web page in the WebView. You should have the HTML file downloaded locally, after which it is quite easy to get it to show in a WebView. This does not automatically show images and other external files! However, I think that kind of defeats the purpose, which is saving on internet costs.

If anyone wants to know how I would do this, please ask in this thread!

To open and display the downloaded HTML in your WebView:

mWebView.loadUrl("file://"
+ Environment
.getExternalStorageDirectory()
.getPath() + "/data/"
+ getPackageName()
+ "/webpage.html");

Very easy, as I said. Just add file:// to the front of your downloaded file's location, and the WebView will do all the work.

You should make sure, though, that the app doesn't have an Internet connection available. I check this when the WebView starts, but that's material for another guide.

I hope this tutorial helped you. Should you still have questions or see something wrong, please do tell me!

Regards,

bassie1995