Android Programming

Android AsyncTask - Download Image/Bitmap

There are plenty of image downloader libraries.Picasso and Glide are so far my best two.However,the truth is they are third party libraries and have to be added as a dependency in android studio or jar in Eclipse.

Sometimes instead of using third party dependencies you just need to do something using the built in classes.

So in this example we see how to download an image/bitmap in the background thread using asynctask.

AsyncTask is an abstract class that makes threading while updating the UI easier.

Our MainActivity Class

Here are the responsibilities for this class:

No. Role
1. It's our launcher activity
2. Define the URL we will connect to download the image
3. Define an inner class that derives from AsyncTask so that we are able to download our image without freezing the UI.
4. Render the an ImageView, a button and a progressbar

Let's go.

First specify the package name:

package com.tutorials.asyncimagedownload;

Then add these imports:

    import java.io.InputStream;
    import java.net.URL;
    import android.app.Activity;
    import android.app.ProgressDialog;
    import android.graphics.Bitmap;
    import android.graphics.BitmapFactory;
    import android.os.AsyncTask;
    import android.os.Bundle;
    import android.view.View;
    import android.view.View.OnClickListener;
    import android.widget.Button;
    import android.widget.ImageView;

Create a class and make it extend android.app.Activity:

public class MainActivity extends Activity {}

Add the following as instance fields. Please give a url containing image:

      private String url="http://10.0.2.2/galacticnews/spacecraft.jpg";
      ImageView img;
      Button downloadBtn;
      ProgressDialog pd;

If your imag is hosted locally then specify the root ip address as I have, that is if you'll be testing in an emulator.

Let's now create an inner class inside our MainActivity. First here are the roles of this inner Downloader class:

No. Role
1. It's responsible for downloading our image in the background thread and rendering it in an imageview.
2. It shows a progress dialog while download in progress and dismisses it when it's over.
private class Downloader {}

Make the class derive from AsyncTask:

private class Downloader extends AsyncTask<String,Void,Bitmap>{}

AsyncTask is an abstract class, hence you'll have to override at least the doInBackground() method. But for us firs we override the onPreExecute().This method will get called before our doInBackground()

            @Override
            protected void onPreExecute() {
                // TODO Auto-generated method stub

                super.onPreExecute();

We'll set up our progressbar and show it here inside the onPreExecute():


                //CREATE PD,SET PROPERTIES
                pd=new ProgressDialog(MainActivity.this);
                pd.setTitle("Image Downloader");
                pd.setMessage("Downloading...");
                pd.setIndeterminate(false);
                pd.show();
            }

We then override the doInBackground(). This is a must since it's here that our background image downloading will be taking place in a separate thread.

@Override
        protected Bitmap doInBackground(String... url) {|

You can see it's returning a Bitmap while taking in a string url. Here's how we download the image. Add the following code inside your doInBackground() method:

           String myurl=url[0];
          Bitmap bm=null;
          InputStream is=null;

          try
          {
            is=new URL(myurl).openStream();

            //DECODE
            bm=BitmapFactory.decodeStream(is);

          }
          catch(Exception e)
          {
            e.printStackTrace();
          }

          return bm;

Then lastly we override the onPostExecute() a method that gets executed when the doInBackground has returned. We set our bitmap to our imageview here and clear the progress dialog.

@Override
        protected void onPostExecute(Bitmap result) {
          // TODO Auto-generated method stub
          super.onPostExecute(result);

          //SET TO IMG
          img.setImageBitmap(result);

           //DISMISS
          pd.dismiss();

        }

Now let's go back inside our MainActivity and override it's onCreate() method:

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

Then refernce our widgets: imageview and download button:

            img=(ImageView) findViewById(R.id.imageView1);
            downloadBtn=(Button) findViewById(R.id.button);

Then inside our download button's onClickListener execute our AsyncTask, passing in the URL:

          @Override
          public void onClick(View arg0) {
            // TODO Auto-generated method stub
            new Downloader().execute(url);
          }
        });

Then make sure you add the permission to internet in your androidmanifest.xml.

<?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.tutorials.asyncimagedownload"
        android:versionCode="1"
        android:versionName="1.0" >

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

        <application
            android:allowBackup="true"
            android:icon="@drawable/ic_launcher"
            android:label="@string/app_name"
            android:theme="@style/AppTheme" >
            <activity
                android:name="com.tutorials.asyncimagedownload.MainActivity"
                android:label="@string/app_name" >
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />

                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
        </application>

    </manifest>

Layout

Just Add ImageView and button to your xml layout.


    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:paddingBottom="@dimen/activity_vertical_margin"
        android:paddingLeft="@dimen/activity_horizontal_margin"
        android:paddingRight="@dimen/activity_horizontal_margin"
        android:paddingTop="@dimen/activity_vertical_margin"
        tools:context=".MainActivity" >

        <Button
            android:id="@+id/button"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_alignParentRight="true"
            android:background="#009968"
            android:layout_marginBottom="58dp"
            android:text="Download" />

        <ImageView
            android:id="@+id/imageView1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_above="@+id/imageView1"
            android:layout_centerHorizontal="true"
            android:layout_marginBottom="43dp"
            android:src="@drawable/imageloading" />

    </RelativeLayout>

And that's it.