在AsyncTasks仍在运行时检测是否已选择刷新按钮

时间:2012-04-21 17:07:48

标签: android synchronization android-listview android-asynctask

我有一个Android应用程序正在使用列表活动来显示从互联网上提取的项目列表。我首先使用AsyncTask加载列表,Async任务完成后调用另一个异步任务开始加载与列表项一起的缩略图。我遇到的问题是用户可以访问他们可以随时按下的刷新按钮,当按下它时,整个项目列表将被删除并且加载重新开始。如果发生这种情况,加载缩略图的异步任务可能仍在运行,并且可能会尝试将缩略图添加到非现有列表项。我试过在列表上进行同步,使用布尔值,经过研究后我发现它不起作用。我还尝试使用静态原子布尔来检查是否已经命中刷新以取消缩略图加载器。有什么想法吗?

public class LoadItems extends AsyncTask<Void, Void, Boolean> {

private Activity activity;
private static boolean loading = false;
public static final AtomicBoolean refreshing = new AtomicBoolean(false);
private static final String TAG = "LoadItems";
private int start;

private List<ListItem> items;

public LoadItems(Activity activity) {
    this.activity = activity;
}

@Override
protected void onPreExecute() {
    loading = true;
    start = ItemViewer.itemList.size();
}

@Override
protected Boolean doInBackground(Void... arg0) {

    items = WebFunctions.getMoreItems(activity);
    return (items != null);
}


protected void onPostExecute(Boolean success) {
    if (success) {
        for (ListItem item: items) {
            ItemViewer.itemList.add(item);
            Log.d(TAG, "added item " + item.getTitle());
        }
        LoadThumbnails thumbnailLoader = new LoadThumbnails();
        thumbnailLoader.execute(start, ItemViewer.itemList.size());
    }
    loading = false;
}

public void protectedExecute() {
    if (!loading)
        execute();
}

public void refresh() {
    if (!refreshing.getAndSet(true)) {
        WebFunctions.reset();
        ItemViewer.itemList.removeAllItems();
        execute();
    }
}

}



public class LoadThumbnails extends AsyncTask<Integer, Void, Drawable> {
private int position;
private int end;

@Override
protected Drawable doInBackground(Integer... params) {
    position = params[0];
    end = params[1];
    Drawable thumbnail = null;
    synchronized(ItemViewer.itemList) {
        if (LoadItems.refreshing.get())
            cancel(true);
        String url = ItemViewer.itemList.get(position).getThumbnailUrl();
        if (!url.isEmpty())
            thumbnail = WebFunctions.loadDrawableFromUrl(ItemViewer.activity, url);
    }
    return thumbnail;
}

protected void onPostExecute(Drawable d) {

    synchronized (ItemViewer.itemList) {
        if (LoadItems.refreshing.get())
            cancel(true);
        if (d != null)
            ItemViewer.itemList.setThumbnail(position, d);
        position++;
        if (position < end) {
            LoadThumbnails lt = new LoadThumbnails();
            lt.execute(position, end);
        }
    }
}

}

2 个答案:

答案 0 :(得分:0)

以下步骤可能有所帮助:

  1. 缓存结果,无论您之前从网络中提取的内容都应该保存,并在应用程序启动时快速恢复。通过这种方式,您可以避免应用程序启动时出现长时间延迟和空屏幕,从而阻止用户按“重新加载”

  2. 制作一个布尔变量reload_in_progress,当您开始从网络中提取数据时将其设置为true,并在所有缩略图准备就绪时将其设置为false。 “重新加载”点击处理程序应该在reload_in_progresstrue时忽略点击次数。

  3. 向用户显示progress bar的某位王,所以他知道它已经重新加载,并且不会再次推送reload

  4. 几乎忘了,永远不会更新向用户显示的数据“直播”,这会带来美妙的情况,当用户点击项目时它会发生变化并做一些与他预期的完全不同的事情。长时间更新应该保留自己的数据,并且只有在一切就绪后才能快速交换新数据。

答案 1 :(得分:0)

这很容易解决。每当用户点击刷新按钮时,请确保在创建新任务之前在最后创建的异步任务上调用cancel()。例如,

private void onRefreshClick(View v) {
  if(mLastLoadItemTask != null) mLastLoadItemTask.cancel(true);
  if(mLastLoadThumbnailTask != null) mLastLoadThumbnailTask.cancel(true);
  mLastLoadItemTask = new LoadItems(...);
  mLastLoadItemTask.execute();
}

然后,在每个异步任务的onPostExecute中,首先通过调用isCancelled()来检查它们是否被取消。如果它们被取消,请确保onPostExecute方法不起作用。例如,

  protected void onPostExecute(...) {   
         if(isCancelled()) return;
         //Adding items to list 
         //Or start load thumbnail task  
     }

正如您所看到的那样,应该可以防止任何无意或过时的更新,因为onPostExecute方法和cancel调用都将在主要的therad上发生。我建议的最后一件事是改变你的loadThumbs任务,以便能够尽快通过检查isCancelled()来停止工作。