Android Lazy Loading images and text in listview from http json data

September 19, 2012
By

In this article, we will create an Android application containing listview with images and text. The listview items are loaded from a remote http json object. The images and text are loaded in listview as they get downloaded to the device.



The whole application can be divided in to three different processes as follows :

1. Download JSON data from http url ( DownloadTask )

2. Parse JSON data and populate listview with text ( ListViewLoaderTask )

3. Download image from http server and populate listview with images at appropriate positions ( ImageLoaderTask)

This article is an extension to the article titled “ListView with Images and Text using Simple Adapter in Android“.

This application is developed in Eclipse ( 4.2.0 ) with ADT plugin ( 20.0.3 ) and Android SDK ( R20.0.3 )



1. Create a new Android application project namely “ListViewWithJSONFromURL”

New Androd Application Project

Figure 1 : New Androd Application Project


2. Design application launcher icon

Design Application launcher icon

Figure 2 : Design Application launcher icon


3. Create a blank activity to define the class MainActivity

Create a blank activity

Figure 3 : Create a blank activity


4. Enter MainActivity class details

Enter MainActivity Details

Figure 4 : Enter MainActivity Details


5. Delete the Android support library, if exists

By default Eclipse ( 4.2.0) adds Android Support Library to  Android application project. For this application, we don’t need to use this support library. So the library file libs/android-support-v4.jar may be removed manually via ProjectExplorer by simply right click on the file and then clicking the menu item “delete”.


6. Create a folder namely “drawable” under the folder “res”


7. Download the given below image to the folder res/drawable


8. Update the file res/values/strings.xml


<resources>
    <string name="app_name">ListViewWithJSONFromURL</string>
    <string name="hello_world">Hello world!</string>
    <string name="menu_settings">Settings</string>
    <string name="title_activity_main">ListView with JSON From URL</string>
    <string name="str_iv_flag">Flag</string>
</resources>


9. Create a custom layout for the listview in res/layout/lv_layout.xml


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

    <TextView
        android:id="@+id/tv_country"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:textSize="20dp"
        android:textStyle="bold" />

    <ImageView
        android:id="@+id/iv_flag"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/tv_country"
        android:layout_centerVertical="true"
        android:padding="5dp"
        android:contentDescription="@string/str_iv_flag" />

    <TextView
        android:id="@+id/tv_country_details"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_toRightOf="@id/iv_flag"
        android:layout_below="@id/tv_country"  />

</RelativeLayout>


10. Update the layout activity_main in the file res/layout/activity_main.xml


<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" >

    <ListView
        android:id="@+id/lv_countries"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        tools:context=".MainActivity" />
</RelativeLayout>


11. Create a JSON parser class in the file src/in/wptrafficanalyzer/listviewwithjsonfromurl/CountryJSONParser.java


package in.wptrafficanalyzer.listviewwithjsonfromurl;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

/** A class to parse json data */
public class CountryJSONParser {

    // Receives a JSONObject and returns a list
    public List<HashMap<String,Object>> parse(JSONObject jObject){

        JSONArray jCountries = null;
        try {
            // Retrieves all the elements in the 'countries' array
            jCountries = jObject.getJSONArray("countries");
        } catch (JSONException e) {
            e.printStackTrace();
        }

        // Invoking getCountries with the array of json object
        // where each json object represent a country
        return getCountries(jCountries);
    }

    private List<HashMap<String, Object>> getCountries(JSONArray jCountries){
        int countryCount = jCountries.length();
        List<HashMap<String, Object>> countryList = new ArrayList<HashMap<String,Object>>();
        HashMap<String, Object> country = null;

        // Taking each country, parses and adds to list object
        for(int i=0; i<countryCount;i++){
            try {
                // Call getCountry with country JSON object to parse the country
                country = getCountry((JSONObject)jCountries.get(i));
                countryList.add(country);

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

        return countryList;
    }

    // Parsing the Country JSON object
    private HashMap<String, Object> getCountry(JSONObject jCountry){

        HashMap<String, Object> country = new HashMap<String, Object>();
        String countryName = "";
        String flag="";
        String language = "";
        String capital = "";
        String currencyCode = "";
        String currencyName = "";

        try {
            countryName = jCountry.getString("countryname");
            flag = jCountry.getString("flag");
            language = jCountry.getString("language");
            capital = jCountry.getString("capital");
            currencyCode = jCountry.getJSONObject("currency").getString("code");
            currencyName = jCountry.getJSONObject("currency").getString("currencyname");

            String details =        "Language : " + language + "\n" +
                                "Capital : " + capital + "\n" +
                                "Currency : " + currencyName + "(" + currencyCode + ")";

            country.put("country", countryName);
            country.put("flag", R.drawable.blank);
            country.put("flag_path", flag);
            country.put("details", details);

        } catch (JSONException e) {
            e.printStackTrace();
        }
        return country;
    }
}


12. Update the class MainActivity in the file src/in/wptrafficanalyzer/listviewwithjsonfromurl/MainActivity.java


package in.wptrafficanalyzer.listviewwithjsonfromurl;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.List;

import org.json.JSONObject;

import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.widget.ListView;
import android.widget.SimpleAdapter;

public class MainActivity extends Activity {

    ListView mListView;

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

        // URL to the JSON data
        String strUrl = "http://wptrafficanalyzer.in/p/demo1/first.php/countries";

        // Creating a new non-ui thread task to download json data
        DownloadTask downloadTask = new DownloadTask();

        // Starting the download process
        downloadTask.execute(strUrl);

        // Getting a reference to ListView of activity_main
        mListView = (ListView) findViewById(R.id.lv_countries);

    }

    /** A method to download json data from url */
    private String downloadUrl(String strUrl) throws IOException{
        String data = "";
        InputStream iStream = null;
        try{
            URL url = new URL(strUrl);

            // Creating an http connection to communicate with url
            HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();

            // Connecting to url
            urlConnection.connect();

            // Reading data from url
            iStream = urlConnection.getInputStream();

            BufferedReader br = new BufferedReader(new InputStreamReader(iStream));

            StringBuffer sb  = new StringBuffer();

            String line = "";
            while( ( line = br.readLine())  != null){
                sb.append(line);
            }

            data = sb.toString();

            br.close();

        }catch(Exception e){
            Log.d("Exception while downloading url", e.toString());
        }finally{
            iStream.close();
        }

        return data;
    }

    /** AsyncTask to download json data */
    private class DownloadTask extends AsyncTask<String, Integer, String>{
        String data = null;
        @Override
        protected String doInBackground(String... url) {
            try{
                data = downloadUrl(url[0]);
            }catch(Exception e){
                Log.d("Background Task",e.toString());
            }
            return data;
        }

        @Override
        protected void onPostExecute(String result) {

            // The parsing of the xml data is done in a non-ui thread
            ListViewLoaderTask listViewLoaderTask = new ListViewLoaderTask();

            // Start parsing xml data
            listViewLoaderTask.execute(result);
        }
    }

    /** AsyncTask to parse json data and load ListView */
    private class ListViewLoaderTask extends AsyncTask<String, Void, SimpleAdapter>{

        JSONObject jObject;
        // Doing the parsing of xml data in a non-ui thread
        @Override
        protected SimpleAdapter doInBackground(String... strJson) {
            try{
                jObject = new JSONObject(strJson[0]);
                CountryJSONParser countryJsonParser = new CountryJSONParser();
                countryJsonParser.parse(jObject);
            }catch(Exception e){
                Log.d("JSON Exception1",e.toString());
            }

            // Instantiating json parser class
            CountryJSONParser countryJsonParser = new CountryJSONParser();

            // A list object to store the parsed countries list
            List<HashMap<String, Object>> countries = null;

            try{
                // Getting the parsed data as a List construct
                countries = countryJsonParser.parse(jObject);
            }catch(Exception e){
                Log.d("Exception",e.toString());
            }

            // Keys used in Hashmap
            String[] from = { "country","flag","details"};

            // Ids of views in listview_layout
            int[] to = { R.id.tv_country,R.id.iv_flag,R.id.tv_country_details};

            // Instantiating an adapter to store each items
            // R.layout.listview_layout defines the layout of each item
            SimpleAdapter adapter = new SimpleAdapter(getBaseContext(), countries, R.layout.lv_layout, from, to);

            return adapter;
        }

        /** Invoked by the Android on "doInBackground" is executed */
        @Override
        protected void onPostExecute(SimpleAdapter adapter) {

            // Setting adapter for the listview
            mListView.setAdapter(adapter);

            for(int i=0;i<adapter.getCount();i++){
                HashMap<String, Object> hm = (HashMap<String, Object>) adapter.getItem(i);
                String imgUrl = (String) hm.get("flag_path");
                ImageLoaderTask imageLoaderTask = new ImageLoaderTask();

                HashMap<String, Object> hmDownload = new HashMap<String, Object>();
                hm.put("flag_path",imgUrl);
                hm.put("position", i);

                // Starting ImageLoaderTask to download and populate image in the listview
                imageLoaderTask.execute(hm);
            }
        }
    }

    /** AsyncTask to download and load an image in ListView */
    private class ImageLoaderTask extends AsyncTask<HashMap<String, Object>, Void, HashMap<String, Object>>{

        @Override
        protected HashMap<String, Object> doInBackground(HashMap<String, Object>... hm) {

            InputStream iStream=null;
            String im
            gUrl = (String) hm[0].get("flag_path");
            int position = (Integer) hm[0].get("position");

            URL url;
            try {
                url = new URL(imgUrl);

                // Creating an http connection to communicate with url
                HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();

                // Connecting to url
                urlConnection.connect();

                // Reading data from url
                iStream = urlConnection.getInputStream();

                // Getting Caching directory
                File cacheDirectory = getBaseContext().getCacheDir();

                // Temporary file to store the downloaded image
                File tmpFile = new File(cacheDirectory.getPath() + "/wpta_"+position+".png");

                // The FileOutputStream to the temporary file
                FileOutputStream fOutStream = new FileOutputStream(tmpFile);

                // Creating a bitmap from the downloaded inputstream
                Bitmap b = BitmapFactory.decodeStream(iStream);

                // Writing the bitmap to the temporary file as png file
                b.compress(Bitmap.CompressFormat.PNG,100, fOutStream);

                // Flush the FileOutputStream
                fOutStream.flush();

               //Close the FileOutputStream
               fOutStream.close();

                // Create a hashmap object to store image path and its position in the listview
                HashMap<String, Object> hmBitmap = new HashMap<String, Object>();

                // Storing the path to the temporary image file
                hmBitmap.put("flag",tmpFile.getPath());

                // Storing the position of the image in the listview
                hmBitmap.put("position",position);

                // Returning the HashMap object containing the image path and position
                return hmBitmap;

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

        @Override
        protected void onPostExecute(HashMap<String, Object> result) {
            // Getting the path to the downloaded image
            String path = (String) result.get("flag");

            // Getting the position of the downloaded image
            int position = (Integer) result.get("position");

            // Getting adapter of the listview
            SimpleAdapter adapter = (SimpleAdapter ) mListView.getAdapter();

            // Getting the hashmap object at the specified position of the listview
            HashMap<String, Object> hm = (HashMap<String, Object>) adapter.getItem(position);

            // Overwriting the existing path in the adapter
            hm.put("flag",path);

            // Noticing listview about the dataset changes
            adapter.notifyDataSetChanged();
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.activity_main, menu);
        return true;
    }
}


13. Update AndroidManifest.xml to provide Internet access permission for this application


<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="in.wptrafficanalyzer.listviewwithjsonfromurl"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="4"
        android:targetSdkVersion="15" />

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

    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".MainActivity"
            android:label="@string/title_activity_main" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>


14. Screenshot of the application

Loading Images and Text in ListView

Figure 5 : Loading Images and Text in ListView


15. Download


16. Reference

http://developer.android.com/guide/index.html


How to hire me?

I am George Mathew, working as software architect and Android app developer at wptrafficanalyzer.in

You can hire me on hourly basis or on project basis for Android applications development.

For hiring me, please mail your requirements to info@wptrafficanalyzer.in.

My other blogs
store4js.blogspot.com


Android Knowledge Quiz

Ready to test your knowledge in Android? Take this quiz :



Tags: , , , , , , , , ,

32 Responses to Android Lazy Loading images and text in listview from http json data

  1. Amit on September 24, 2012 at 11:32 am

    Thanks to post this incredible work
    but i want to call different intents from each listview item with specified webURL, like:- if user will click on first row, then we will call separate url to fetch the record( “http://ta.wptrafficanalyzer.in/demo1/first.php/countries/india/”;
    ), for second row ( “http://ta.wptrafficanalyzer.in/demo1/first.php/countries/japan/”) and so on.Please do these changes and i am confident after these changes this post will be most useful for many developers like me..

    • george on September 24, 2012 at 12:30 pm

      Thanks for the suggestion

    • gaurang jhawar on November 27, 2012 at 6:56 pm

      HOW TO IMPLEMENT ONCLICK IN THE SAME CODE I.E. WHEN I CLICK A PARTICULAR LIST ITEM A POPUP APPEARS REPEATING ALL THE DETAILS AND HAVING A CLICKABLE BUTTON IN IT?????

      • Naren Lee on May 9, 2014 at 3:29 pm

        HOW TO IMPLEMENT ONCLICK IN THE SAME CODE I.E. WHEN I CLICK A PARTICULAR LIST ITEM A POPUP APPEARS REPEATING ALL THE DETAILS AND HAVING A CLICKABLE BUTTON IN IT?????

        • Naren Lee on May 9, 2014 at 3:38 pm

          I have the same question.If anyone has the answer please let me know.

  2. Raam Kumar on September 28, 2012 at 11:36 am

    Hey,
    Thanks for such a nice post.following is my issue,
    it works when i download 3-4 images and display it in listview along with some text, but it crashes immediately when I try to download more than 5 images.Please give me some solution.I need it desperately.

    Thanks in advance

  3. surya on December 4, 2012 at 11:30 am

    i downloaded this code but it is displaying force close. why is this happening do any one faced the problem?

    • george on December 5, 2012 at 6:47 am

      Hello Surya,
      Thank you for reporting this.
      If you are getting UnknownHostException in logcat, then it is due to a change in the URL. The URL is updated now. Please see the code.

  4. vezikon on December 5, 2012 at 3:38 am

    Thanks for this code .. This’s actually a great
    but I’m wondering is there more faster way to this or not ?!

    • Vipin on December 15, 2012 at 4:07 pm

      I found another simple one, try this..

      coderzheaven.com/2012/09/23/simplest-lazy-loading-listview-android-data-populated-mysql-database-php/

  5. vishal on January 28, 2013 at 2:57 pm

    i have download the source code,but it give force closing……
    i can i do…it also give
    01-28 14:40:02.324: E/AndroidRuntime(429): FATAL EXCEPTION: main

    nullpointer Exception..

    • Rajesh koshti on August 24, 2014 at 2:44 pm

      add a uses permission INTERNET in android manifest file in your project . ;)

  6. Ankit on February 11, 2013 at 11:10 pm

    Thanks for this code. I have download the source code and it works fine. But when i change the url, it fetched the data but when i try to download the image and put it into the hashmap it gives me lots of error and exception. I got java.io.IOExceptio: Is a directory. How to resolve it. Help me to resolve this error.

    • george on February 12, 2013 at 5:06 am

      Hello Ankit,
      Please ensure that, the images are available in your specified url.

  7. Dhruv on February 16, 2013 at 3:26 pm

    Hey george,
    i am using same concept as you implement. But i got an error.
    “java.lang.OutOfMemoryError: bitmap size exceeds VM budget”

  8. paul on February 24, 2013 at 7:58 pm

    how to at loadmore button to this listview demo?

  9. wedar on April 8, 2013 at 6:08 am

    Hai can you show me hoe to implement this Activity with Fragment?. Thanks, sorry my english is bad

  10. ankit patel on April 14, 2013 at 11:07 am

    thanks for example

    but when i try to run your code with froyo 2.2

    i got the null pointer exception on line
    SimpleAdapter adapter = (SimpleAdapter ) mListView.getAdapter();

    please tell me what is the problem

  11. Rajesh on July 15, 2013 at 5:12 pm

    Its a nice article n very useful
    Thanks for sharing

  12. Russel on July 27, 2013 at 11:08 pm

    Thanks for the code …. i edited it with my own php script,images and data and it works fine …. though if it cannot connect to a database it crashes ….is it possible to just display a popup informing the user a connection is not available ?

  13. Guillermo on August 5, 2013 at 4:59 am

    Thanks for useful code, is posible to obtain the json script code generator and other related info like Database?. thanks so much for your help.

  14. mangesh kaduskar on August 5, 2013 at 3:12 pm

    i implement this code in my application with asynctask. but now i want download more data and append it to bottom of listview. i took one button and onclick event i called that asyntask again but it shows me only one data in listview.
    Please suggest me how i can implement it.

  15. Hussein Hajjali on September 6, 2013 at 3:16 pm

    hi
    please can you give me the php code of
    http://wptrafficanalyzer.in/p/demo1/first.php/countries/
    I’m new in json parse

  16. javier Cervantes on October 1, 2013 at 7:01 am

    thanks, the tutorial is perfect très très bien :P
    i begin in android 8 days to be exact and perfect many thanks

  17. Anas on October 4, 2013 at 6:45 pm

    Thank your for your post.
    I’m developing an Application, I retrieve texts and images from the server using JSON , and i want to display these texts and images in customized layout instead of using listview , can i do that ?
    I designed an activity and i want to set theses texts and images using iflater, every view has two texts and one image

  18. Deepu on October 15, 2013 at 3:06 pm

    First of all thanks for the code. The problem is that i cant load more than 20 images at a time,then it shows time out exception. Is there any solution to overcome this error. Please answer me

  19. Manish on November 13, 2013 at 4:46 pm

    I am using the same code.. But In Mine case default image is shown but the URL Image is not display .. Please help.. also I want to make this listview clickable to show more detail information about country . Any idea about that.

  20. seamoon31 on December 11, 2013 at 11:54 am

    thank you. your guide is very good. this mention is short, but my mind is real. :)

  21. Harry Chawla on December 20, 2013 at 3:07 pm

    Thanks, its working fine. I need your assistance as when we are loading content from url can we display loading progress bar over their at images location. I am working on that created the Async class too. But getting issue in that. If you have any example like that can provide me information regarding that.

  22. didier castillo on January 28, 2014 at 2:31 am

    Hi, George I really liked your app worked well, my question is, how can I do, when I click the item to send me an activity with more description of that country, and tried many ways but still can

  23. harsha on February 26, 2014 at 1:44 pm

    Hi Mathew, very helpful tutorial. Am getting the image name not url. Plese share your php files.Thank you

  24. KalyanSrinivas on May 27, 2014 at 3:06 pm

    Thanks a lot
    saved my time
    very good tutorial

Leave a Reply

Your email address will not be published. Required fields are marked *

Be friend at g+

Subscribe for Lastest Updates

FBFPowered by ®Google Feedburner