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”
2. Design application launcher icon
3. Create a blank activity to define the class MainActivity
4. Enter MainActivity class 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
15. Download
16. Reference
http://developer.android.com/guide/index.html





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..
Thanks for the suggestion
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?????
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
i downloaded this code but it is displaying force close. why is this happening do any one faced the problem?
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.
Thanks for this code .. This’s actually a great
but I’m wondering is there more faster way to this or not ?!
I found another simple one, try this..
coderzheaven.com/2012/09/23/simplest-lazy-loading-listview-android-data-populated-mysql-database-php/
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..
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.
Hello Ankit,
Please ensure that, the images are available in your specified url.
Hey george,
i am using same concept as you implement. But i got an error.
“java.lang.OutOfMemoryError: bitmap size exceeds VM budget”
how to at loadmore button to this listview demo?
Hai can you show me hoe to implement this Activity with Fragment?. Thanks, sorry my english is bad
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