Issue
So, I am starting an AsyncTask when activity starts. I am trying to implement infinite listview. When user scrolls to the bottom of listview, an AsyncTask should start to bring new data. Meanwhile, If user scrolls up and scrolls down again to the bottom, this is where i get error.
Following is the code I tried:
import java.util.ArrayList;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import android.app.ProgressDialog;
import android.content.Context;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.view.MenuItemCompat;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.widget.SearchView;
import android.support.v7.widget.SearchView.OnQueryTextListener;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;
import android.widget.Toast;
public class CaseListingActivity extends ActionBarActivity {
ListView mListViewCase;
ArrayList<CaseDetails> mArrayList;
CaseListAdapter mCaseListAdapter;
View mView;
CaseListingTask mCaseListingTask;
int preLast;
int currentPage = 1;
public static final String URL = "http://xxxxxx.xxxxxxx/DC.svc/rest/GetSubject?PageNo=";
public static final String GET_SUBJECT_RESULT = "GetSubjectResult";
public static final String ID = "Id";
public static final String SUB = "Sub";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_case_listing);
mArrayList = new ArrayList<CaseDetails>();
mCaseListAdapter = new CaseListAdapter(this, mArrayList);
mCaseListingTask = new CaseListingTask();
mView = ((LayoutInflater) this
.getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(
R.layout.listview_footer, null, false);
mListViewCase = (ListView) findViewById(R.id.listViewCaseListing);
mListViewCase.addFooterView(mView);
mListViewCase.setAdapter(mCaseListAdapter);
mListViewCase.setOnScrollListener(new OnScrollListener() {
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
// TODO Auto-generated method stub
// if (scrollState == SCROLL_STATE_IDLE) {
// if (mListViewCase.getLastVisiblePosition() >= mListViewCase
// .getCount() - 1 - 1) {
//
// // if (mCaseListingTask.getStatus() !=
// AsyncTask.Status.RUNNING) {
// //
// // }
// if (mCaseListingTask.getStatus() == AsyncTask.Status.RUNNING)
// {
// // Do Something?
// } else {
// currentPage++;
// // load more list items:
// mCaseListingTask.execute(URL + currentPage);
// }
// }
// }
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
// TODO Auto-generated method stub
switch (view.getId()) {
case R.id.listViewCaseListing:
// Make your calculation stuff here. You have all your
// needed info from the parameters of this function.
// Sample calculation to determine if the last
// item is fully visible.
final int lastItem = firstVisibleItem + visibleItemCount;
if (lastItem == totalItemCount) {
// if (preLast != lastItem) { // to avoid multiple calls
// // for last item
// Log.d("Last", "Last");
// preLast = lastItem;
if (mCaseListingTask.getStatus() == AsyncTask.Status.FINISHED) {
currentPage++;
// load more list items:
mCaseListingTask.execute(URL + currentPage);
}
// }
}
}
}
});
mListViewCase.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
long arg3) {
// TODO Auto-generated method stub
Toast.makeText(getBaseContext(),
arg0.getItemAtPosition(arg2).toString(),
Toast.LENGTH_SHORT).show();
}
});
new CaseListingTask().execute(URL + currentPage);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// TODO Auto-generated method stub
getMenuInflater().inflate(R.menu.menu, menu);
MenuItem searchItem = menu.findItem(R.id.action_search);
SearchView searchView = (SearchView) MenuItemCompat
.getActionView(searchItem);
searchView.setOnQueryTextListener(new OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String arg0) {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean onQueryTextChange(String arg0) {
// TODO Auto-generated method stub
return false;
}
});
return super.onCreateOptionsMenu(menu);
}
public class CaseListingTask extends AsyncTask<String, Void, String> {
ProgressDialog mProgressDialog;
@Override
protected String doInBackground(String... params) {
// TODO Auto-generated method stub
String result = "";
for (String string : params) {
result = new JSONParser().getJSONFromUrl(string);
}
return result;
}
/*
* (non-Javadoc)
*
* @see android.os.AsyncTask#onPostExecute(java.lang.Object)
*/
@Override
protected void onPostExecute(String result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
try {
JSONObject mJsonObject = new JSONObject(result);
JSONArray mJsonArray = mJsonObject
.getJSONArray(GET_SUBJECT_RESULT);
for (int i = 0; i < mJsonArray.length(); i++) {
JSONObject c = mJsonArray.getJSONObject(i);
mArrayList.add(new CaseDetails(c.getInt(ID), c
.getString(SUB)));
}
mCaseListAdapter.notifyDataSetChanged();
mListViewCase.removeFooterView(mView);
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/*
* (non-Javadoc)
*
* @see android.os.AsyncTask#onPreExecute()
*/
@Override
protected void onPreExecute() {
// TODO Auto-generated method stub
super.onPreExecute();
// mProgressDialog = ProgressDialog.show(CaseListingActivity.this,
// "Please Wait...", "Loading...", true, false);
mListViewCase.addFooterView(mView, null, false);
}
}
}
If you need more details, please ask for it. Thanks.
Solution
The problem is simple: You can execute every AsyncTask
only once. From the documentation of AsyncTask:
There are a few threading rules that must be followed for this class to work properly:
- The AsyncTask class must be loaded on the UI thread. This is done automatically as of JELLY_BEAN.
- The task instance must be created on the UI thread.
- execute(Params...) must be invoked on the UI thread.
- Do not call onPreExecute(), onPostExecute(Result), doInBackground(Params...), onProgressUpdate(Progress...) manually.
- The task can be executed only once (an exception will be thrown if a second execution is attempted.)
You create a new instance of CaseListingTask
in onCreate()
and try to reuse this same instance in your OnScrollListener
. What you have to do is create a new instance of CaseListingTask
every time you want to run it.
So to summarise replace this:
if (mCaseListingTask.getStatus() == AsyncTask.Status.FINISHED) {
currentPage++;
// load more list items:
mCaseListingTask.execute(URL + currentPage);
}
With this:
if (mCaseListingTask.getStatus() == AsyncTask.Status.FINISHED) {
currentPage++;
mCaseListingTask = new CaseListingTask();
mCaseListingTask.execute(URL + currentPage);
}
Answered By - Xaver Kapeller
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.