android:如果一个 AsyncTask 已经在运行,则阻止另一个 AsyncTask 执行
Posted
技术标签:
【中文标题】android:如果一个 AsyncTask 已经在运行,则阻止另一个 AsyncTask 执行【英文标题】:android: prevent another AsyncTask from executing if one is already running 【发布时间】:2014-10-06 16:39:48 【问题描述】:所以,我在活动开始时启动 AsyncTask。我正在尝试实现无限列表视图。当用户滚动到列表视图的底部时,AsyncTask 应该开始带来新数据。同时,如果用户向上滚动并再次向下滚动到底部,这就是我得到错误的地方。
以下是我试过的代码:
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);
如果您需要更多详细信息,请询问。谢谢。
【问题讨论】:
您遇到什么错误?如果遇到异常,始终在问题中包含 logcat。 @XaverKapeller 当然先生。等一下。 @XaverKapeller 抱歉,我无法重现它。因为我正在尝试使用不同的代码。但现在的情况是另一项任务还没有开始。 我已经从问题本身回滚了您的解决方案。你可以找到它in the revision history。请直接将其发布为答案。 【参考方案1】:问题很简单:每个AsyncTask
只能执行一次。来自the documentation of AsyncTask:
这个类必须遵循一些线程规则 正常工作:
必须在 UI 线程上加载 AsyncTask 类。这从 JELLY_BEAN 开始自动完成。 必须在 UI 线程上创建任务实例。 execute(Params...) 必须在 UI 线程上调用。 不要手动调用 onPreExecute()、onPostExecute(Result)、doInBackground(Params...)、onProgressUpdate(Progress...)。 任务只能执行一次(如果尝试第二次执行会抛出异常。)
您在onCreate()
中创建了一个CaseListingTask
的新实例,并尝试在您的OnScrollListener
中重复使用这个相同的实例。你需要做的是每次你想运行它时创建一个CaseListingTask
的新实例。
所以总结一下替换这个:
if (mCaseListingTask.getStatus() == AsyncTask.Status.FINISHED)
currentPage++;
// load more list items:
mCaseListingTask.execute(URL + currentPage);
有了这个:
if (mCaseListingTask.getStatus() == AsyncTask.Status.FINISHED)
currentPage++;
mCaseListingTask = new CaseListingTask();
mCaseListingTask.execute(URL + currentPage);
【讨论】:
谢谢先生。我正在尝试......我会通知你它是否有效。 我发布了工作解决方案。但我仍然不明白为什么需要mCaseListingTask = new CaseListingTask();
。请介意解释一下。
谢谢先生。为您的解决方案。
好的。我明白你的意思了。你提到的Threading Rules
的最后一点。再次感谢。以上是关于android:如果一个 AsyncTask 已经在运行,则阻止另一个 AsyncTask 执行的主要内容,如果未能解决你的问题,请参考以下文章
android中 如果要你来设计AsyncTask,你怎么设计
Android Socket,AsyncTask,Handler内存泄漏