如何防止 AsyncTask 在 onScroll 事件中被多次执行?

How would I prevent AsyncTask from being executed multiple times in onScroll event?

我有一个 AsyncTask,它在 onPostExecute 事件中刷新我的 listView 并在 doInBackground 事件中检索一些数据。问题是我的 AsyncTask 在 onScroll 事件中被执行了多次。我怎样才能阻止它这样做? 顺便说一下,我正在尝试在我的应用程序中创建一个 Infinite Scroll。也许我做错了什么? 这是我的 onScroll 事件:

@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
    previousTotal = totalItemCount;
    try {
        itemNews = listAdapter.getData();
    }catch (Exception e){
        System.out.println("itemNews is empty");
    }
    if(totalItemCount > 2) {
        artId = itemNews.get(firstVisibleItem).articleId;
    }
    if(firstVisibleItem > ((previousTotal)/2))
    {
        UpdateListAsyncTask updateListAsyncTask = new UpdateListAsyncTask(artId, mActivity, listAdapter);
        updateListAsyncTask.execute();
    }

这是我的 AsyncTask:

public class UpdateListAsyncTask extends AsyncTask<Void, Void, Void> {
    public int currentArticleId;
    public Activity mActivity;
    RemoteData remoteData;
    public ListAdapterRegular listAdapter;
    UpdateListAsyncTask(int currentArticleId, Activity activity, ListAdapterRegular listAdapterRegular)
    {
        this.mActivity = activity;
        this.currentArticleId = currentArticleId;
        this.listAdapter = listAdapterRegular;
    }
    @Override
    protected void onPreExecute()
    {
        remoteData = new RemoteData(mActivity, "News");
    }
    @Override
    protected Void doInBackground(Void... params) {
        try{
            remoteData.writeServerData("&from=" + currentArticleId);
            System.out.println("DoInBackground writeServerData");
        }catch (Exception e)
        {
            e.printStackTrace();
            System.out.println("UpdateListAsyncTask: doInBackground exception!");
        }
        return null;
    }

    @Override
    protected void onPostExecute(Void result)
    {
        List<News> dataList = Select.from(News.class).orderBy("date DESC").list();
        System.out.println("onPostExecuteInitiated");
        listAdapter.clear();
        listAdapter.addAll(dataList);
        listAdapter.notifyDataSetChanged();
    }
}

非常感谢任何帮助和想法! 更新: 我不得不重做我的代码,但这是值得的。我是按照link做的:https://github.com/codepath/android_guides/wiki/Endless-Scrolling-with-AdapterViews

我会用这样的东西

// The total number of items in the dataset after the last load
private int previousTotalItemCount = 0;
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
    previousTotal = totalItemCount;
    try {
        itemNews = listAdapter.getData();
    }catch (Exception e){
        System.out.println("itemNews is empty");
    }

    // If the total item count is zero and the previous isn't, assume the
    // list is invalidated and should be reset back to initial state
    if (totalItemCount < previousTotalItemCount) {
        this.previousTotalItemCount = totalItemCount;
        if (totalItemCount == 0) { this.loading = true; } 
    }

    if(totalItemCount > 2) {
        artId = itemNews.get(firstVisibleItem).articleId;
    }

    // If it’s still loading, we check to see if the dataset count has
    // changed, if so we conclude it has finished loading and update the current page
    // number and total item count.
    if(loading && totalItemCount > previousTotalItemCount) {
        loading = false;
        previousTotalItemCount = totalItemCount;
    }

    if(!loading && firstVisibleItem > ((previousTotal)/2))
    {
        loading = true;
        UpdateListAsyncTask updateListAsyncTask = new UpdateListAsyncTask(artId, mActivity, listAdapter);
        updateListAsyncTask.execute();
    }
}

PS 当我实现无限滚动时,我用这个作为例子 https://github.com/codepath/android_guides/wiki/Endless-Scrolling-with-AdapterViews

您的方法可以有其他改进,但没有任何改进,如果您想要的只是多个异步任务而不是 运行,为什么不试试这个?

改变

if(firstVisibleItem > ((previousTotal)/2))
{
    UpdateListAsyncTask updateListAsyncTask = new UpdateListAsyncTask(artId, mActivity, listAdapter);
    updateListAsyncTask.execute();
}

if(firstVisibleItem > ((previousTotal)/2))
{
    if(mUpdateListAsyncTask != null && (mUpdateListAsyncTask.getStatus == AsyncTask.Status.RUNNING|| mUpdateListAsyncTask.getStatus ==AsyncTask.Status.PENDING)) {
         return;
     } else {
         mUpdateListAsyncTask = new UpdateListAsyncTask(artId, mActivity, listAdapter);
         updateListAsyncTask.execute();
     }
 }

基本上,如果状态为 运行 或 PENDING,只需跳过创建新的异步任务并 运行 将其启动。应该可以。

您可能想执行最后一个任务,所以我将 UpdateListAsyncTask updateListAsyncTask 设为属性。

现在改变这个:

if(firstVisibleItem > ((previousTotal)/2))
{
    UpdateListAsyncTask updateListAsyncTask = new UpdateListAsyncTask(artId, mActivity, listAdapter);
    updateListAsyncTask.execute();
}

对此:

if(firstVisibleItem > ((previousTotal)/2))
{
    try{
        updateListAsyncTask.cancel(true);
    }catch(Exception ex){}

    updateListAsyncTask = new     UpdateListAsyncTask(artId, mActivity, listAdapter);
    updateListAsyncTask.execute();
}
private UpdateListAsyncTask updateListAsyncTask = null;

...
if(firstVisibleItem > ((previousTotal)/2))
    {
//Create just if not exist or if it's finished
    if (updateListAsyncTask == null || updateListAsyncTask.getStatus() == Status.FINISHED) {
        updateListAsyncTask = new UpdateListAsyncTask(artId, mActivity, listAdapter);
    }

//Start only if it's not already running
    if (updateListAsyncTask.getStatus() == Status.PENDING) {
        updateListAsyncTask.execute();
    }
}