How to display images on ImageView from json data in Android

advertisements

I am getting json data. In that json I have a url for an image. Now I want to display that Image in ImageView. How can I do acheive this? Here is my code

class LoadInbox extends AsyncTask<String, String, String> {
    /**
     * Before starting background thread Show Progress Dialog
     * */
    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        pDialog = new ProgressDialog(Home.this);
        pDialog.setMessage("Loading Inbox ...");
        pDialog.setIndeterminate(false);
        pDialog.setCancelable(false);
        pDialog.show();
    }

    /**
     * getting Inbox JSON
     * */
 protected String doInBackground(String... arg0) {
        // Building Parameters
        List<NameValuePair> params = new ArrayList<NameValuePair>();

        JSONObject json = userFunctions.homeData();

        Log.e("Data", json.toString());

        // Check your log cat for JSON reponse
        Log.d("Inbox JSON: ", json.toString());

        try {
            data = json.getJSONArray(TAG_DATA);
            Log.d("inbox array: ", data.toString());
            // looping through All messages
            for (int i = 0; i < data.length(); i++) {
                JSONObject c = data.getJSONObject(i);

                // Storing each json item in variable
                String profile_img = c.getString(TAG_PROFILE_IMG);

                // creating new HashMap
                HashMap<String, String> map = new HashMap<String, String>();

                // adding each child node to HashMap key => value
                map.put(TAG_PROFILE_IMG, profile_img);

                // adding HashList to ArrayList
                inboxList.add(map);
            }
        } catch (JSONException e) {
            e.printStackTrace();
        }

        return null;
    }
protected void onPostExecute(String file_url) {
        // dismiss the dialog after getting all products
        pDialog.dismiss();
        // updating UI from Background Thread
        runOnUiThread(new Runnable() {
            public void run() {
                /**
                 * Updating parsed JSON data into ListView
                 * */
                ListAdapter adapter = new SimpleAdapter(
                        Home.this, inboxList,
                        R.layout.home_list_item, new String[] { TAG_PROFILE_IMG },
                        new int[] { R.id.profile_img2 });
                // updating listview
                setListAdapter(adapter);
            }
        });

    }

here is my layout

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >

<ImageView
    android:id="@+id/profile_img2"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:paddingTop="8dip"
    android:paddingLeft="8dip"
    android:paddingBottom="4dip" />
</RelativeLayout>


So you'll want to create another AsyncTask that given a URL will load the image, and populate some control. I typically do something like this:

ImageView imageView = (ImageView)findById(R.id.blah);
new ImageLoader( person.getImageUri(), imageView, 128, 128 ).execute();

The ImageLoader would be another AsyncTask like this:

public class ImageLoader extends AsyncTask<URI,Integer,BitmapDrawable> {
    private Uri imageUri;

    private ImageView imageView;

    private int preferredWidth = 80;
    private int preferredHeight = 80;

    public ImageLoader( URI uri, ImageView imageView, int scaleWidth, int scaleHeight ) {
        this.imageUri = uri;
        this.imageView = imageView;
        this.preferredWidth = scaleWidth;
        this.preferredHeight = scaleHeight;
    }

    public BitmapDrawable doInBackground(URI... params) {
    if( imageUri == null ) return null;
    String url = imageUri.toString();
    if( url.length() == 0 ) return null;
    HttpGet httpGet = new HttpGet(url);
    DefaultHttpClient client = new DefaultHttpClient();
    HttpResponse response = client.execute( httpGet );
    InputStream is = new BufferedInputStream( response.getEntity().getContent() );
    try {
        Bitmap bitmap = BitmapFactory.decodeStream(is);
        if( preferredWidth > 0 && preferredHeight > 0 && bitmap.getWidth() > preferredWidth && bitmap.getHeight() > preferredHeight ) {
            return Bitmap.createScaledBitmap(bitmap, preferredWidth, preferredHeight, false);
        } else {
            return bitmap;
        }
    } finally {
        is.close();
    }
    }
}

    public void onPostExecute( BitmapDrawable drawable ) {
        imageView.setImageBitmap( drawable );
    }
}

Then you can kick this AsyncTask off when the image is being bound in your ListView by creating your own subclass ListAdapter. So you'll have to ditch using SimpleAdapter because things aren't simple anymore. This has a lot of advantages so you only load the images being displayed. That means a very small number is loaded out of the total. Also your user can see the data before the image loads so quicker access to the data. If you did this in your existing AsyncTask you'd load every image, and the user would have to wait for every single one to finish before the data is shown to the user. There are somethings that can be improved by this. One AsyncTask uses its own thread so you'll be running a lot of threads potentially (10 or more) all at once. That can kill your server with lots of clients. You can centralize these using an ExecutorService (ie thread pool) but you'll have to ditch using AsyncTask and implement your own facility to run the job off the UI thread and post the results back on the UI thread. Second, your images will load every time the user scrolls. For this I implemented my own caching scheme based on the URI of the image so I only load the image once and return it from the cache. It's a little too much code to post here, but these are exercises for the reader.

Also notice I'm not posting back to the UI thread in onPostExecute(). That's because AsyncTask does that for me I don't have to do it again as your code above shows. You should just remove that extra runnable and inline the code in onPostExecute().