Chintan Soni
Chintan Soni

Reputation: 25267

android: prevent another AsyncTask from executing if one is already running

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.

Upvotes: 0

Views: 276

Answers (1)

Xaver Kapeller
Xaver Kapeller

Reputation: 49817

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);
}

Upvotes: 1

Related Questions