ListView
.This project load data (JSON) from an URL to parse. Project descriptions:
- Loading JSON data from an URL by using an
AsyncTask
and parse it to my own object. - In
ListView
, showing only 5 items for first time. - Using
OnScrollListener()
forListView
to detect scrolling reach to it's bottom. - Continue loading data and show in
ListView
.
Update info
With Material Design technology,
RecyclerView
is the alternate widget for ListView
in creating list view/table view now. Please read my newer post if you would like to make an endless RecyclerView
with a ProgressBar
at the bottom when data is loading...
2. Create an own POJO to use for
ListView
item:
CountryInfor.java
3. Custom an package com.blogspot.hongthaiit.androidloadmorelistview;
public class CountryInfor {
private String id;
private String name;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
AsyncTask
to downloading data from Internet:
LoadCountriesFromUrlTask.java
4. Create an activity to run:package com.blogspot.hongthaiit.androidloadmorelistview;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONException;
import org.json.JSONObject;
import android.app.Activity;
import android.app.ProgressDialog;
import android.os.AsyncTask;
import android.util.Log;
public class LoadCountriesFromUrlTask extends AsyncTask<Void, Void, String> {
private Activity activity;
private String url;
private ProgressDialog dialog;
private final static String TAG = LoadCountriesFromUrlTask.class.getSimpleName();
public LoadCountriesFromUrlTask(Activity activity, String url) {
super();
this.activity = activity;
this.url = url;
}
@Override
protected void onPreExecute() {
super.onPreExecute();
// Create a progress dialog
dialog = new ProgressDialog(activity);
// Set progress dialog title
dialog.setTitle("ListView Load More Tutorial");
// Set progress dialog message
dialog.setMessage("Loading more...");
dialog.setIndeterminate(false);
// Show progress dialog
dialog.show();
}
@Override
protected String doInBackground(Void... params) {
// call load JSON from url method
return loadJSON(this.url).toString();
}
@Override
protected void onPostExecute(String result) {
((MainActivity) activity).parseJsonResponse(result);
dialog.dismiss();
Log.i(TAG, result);
}
public JSONObject loadJSON(String url) {
// Creating JSON Parser instance
JSONParser jParser = new JSONParser();
// getting JSON string from URL
JSONObject json = jParser.getJSONFromUrl(url);
return json;
}
private class JSONParser {
private InputStream is = null;
private JSONObject jObj = null;
private String json = "";
// constructor
public JSONParser() {
}
public JSONObject getJSONFromUrl(String url) {
// Making HTTP request
try {
// defaultHttpClient
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost(url);
HttpResponse httpResponse = httpClient.execute(httpPost);
HttpEntity httpEntity = httpResponse.getEntity();
is = httpEntity.getContent();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(is, "iso-8859-1"),
8);
StringBuilder sb = new StringBuilder();
String line = null;
while ((line = reader.readLine()) != null) {
sb.append(line + "\n");
}
is.close();
json = sb.toString();
} catch (Exception e) {
Log.e("Buffer Error", "Error converting result " + e.toString());
}
// try parse the string to a JSON object
try {
jObj = new JSONObject(json);
} catch (JSONException e) {
Log.e("JSON Parser", "Error parsing data " + e.toString());
}
// return JSON String
return jObj;
}
}
}
- It's layout simple like this:
activity_main.xml
- In activity programmatically code, we must set <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" >
<LinearLayout
android:id="@+id/layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#000055"
android:orientation="horizontal" >
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/country"
android:textColor="@android:color/white"
android:textSize="22sp" />
</LinearLayout>
<ListView
android:id="@+id/list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/layout"
android:scrollbars="none" />
</RelativeLayout>
OnScrollListener
for the ListView
:
private OnScrollListener onScrollListener() {
return new OnScrollListener() {
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
int threshold = 1;
int count = listView.getCount();
if (scrollState == SCROLL_STATE_IDLE) {
if (listView.getLastVisiblePosition() >= count - threshold && pageCount < 2) {
Log.i(TAG, "loading more data");
// Execute LoadMoreDataTask AsyncTask
getDataFromUrl(url_page2);
}
}
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
int totalItemCount) {
}
};
}
MainActivity.java
5. Layout for each package com.blogspot.hongthaiit.androidloadmorelistview;
import java.util.ArrayList;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import android.app.Activity;
import android.app.ProgressDialog;
import android.os.Bundle;
import android.util.Log;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.ListView;
public class MainActivity extends Activity {
private final static String url_page1 = "http://www.json-generator.com/api/json/get/ckDtZPkgJe?indent=2";
private final static String url_page2 = "http://www.json-generator.com/api/json/get/bVifgkcmxu?indent=2";
private final static String TAG = MainActivity.class.getSimpleName();
private int pageCount = 0;
private CountryAdapter adapter;
private ListView listView;
private ProgressDialog dialog;
private ArrayList<CountryInfor> countries;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listView = (ListView) findViewById(R.id.list);
setListViewAdapter();
getDataFromUrl(url_page1);
listView.setOnScrollListener(onScrollListener());
}
private void setListViewAdapter() {
countries = new ArrayList<CountryInfor>();
adapter = new CountryAdapter(this, R.layout.item_listview, R.id.country_name, countries);
listView.setAdapter(adapter);
}
// calling asynctask to get json data from internet
private void getDataFromUrl(String url) {
new LoadCountriesFromUrlTask(this, url).execute();
}
private OnScrollListener onScrollListener() {
return new OnScrollListener() {
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
int threshold = 1;
int count = listView.getCount();
if (scrollState == SCROLL_STATE_IDLE) {
if (listView.getLastVisiblePosition() >= count - threshold && pageCount < 2) {
Log.i(TAG, "loading more data");
// Execute LoadMoreDataTask AsyncTask
getDataFromUrl(url_page2);
}
}
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
int totalItemCount) {
}
};
}
//parsing json after getting from Internet
public void parseJsonResponse(String result) {
Log.i(TAG, result);
pageCount++;
try {
JSONObject json = new JSONObject(result);
JSONArray jArray = new JSONArray(json.getString("message"));
for (int i = 0; i < jArray.length(); i++) {
JSONObject jObject = jArray.getJSONObject(i);
CountryInfor country = new CountryInfor();
country.setId(jObject.getString("id"));
country.setName(jObject.getString("name"));
countries.add(country);
}
adapter.notifyDataSetChanged();
if (dialog != null) {
dialog.dismiss();
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}
ListView
row:
item_listview.xml
6. Custom a <LinearLayout 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" >
<TextView
android:id="@+id/country_name"
android:layout_width="wrap_content"
android:layout_height="150dp"
android:layout_gravity="center"
android:gravity="center"
android:drawableLeft="@drawable/earth"
android:drawablePadding="10dp"
android:textColor="@android:color/holo_green_dark"
android:textSize="20sp" />
</LinearLayout>
ListView
adapter based on ArrayAdapter
:
CountryAdapter.java
7. Open your AndroidManifest.xml file and add Internet permission:
package com.blogspot.hongthaiit.androidloadmorelistview;
import java.util.List;
import android.app.Activity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;
public class CountryAdapter extends ArrayAdapter<CountryInfor> {
private Activity activity;
public CountryAdapter(Activity activity, int resource, int textViewResourceId,
List<CountryInfor> countries) {
super(activity, resource, textViewResourceId, countries);
this.activity = activity;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
LayoutInflater inflater =
(LayoutInflater) activity.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
// If holder not exist then locate all view from UI file.
if (convertView == null) {
// inflate UI from XML file
convertView = inflater.inflate(R.layout.item_listview, parent, false);
// get all UI view
holder = new ViewHolder(convertView);
// set tag for holder
convertView.setTag(holder);
} else {
// if holder created, get tag from view
holder = (ViewHolder) convertView.getTag();
}
CountryInfor country = getItem(position);
holder.countryName.setText(country.getName());
holder.countryName.setCompoundDrawablesWithIntrinsicBounds(R.drawable.earth, 0, 0, 0);
return convertView;
}
private static class ViewHolder {
private TextView countryName;
public ViewHolder(View v) {
countryName = (TextView) v.findViewById(R.id.country_name);
}
}
}
AndroidManifest.xml
8. Build and run program, we'll see our result: :D
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.blogspot.hongthaiit.androidloadmorelistview"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="14"
android:targetSdkVersion="21" />
<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=".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>
(sorry for ads)