0

我有一个 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);
        }
    }
}

}
4

2 回答 2

0

以下步骤可能会有所帮助:

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

  2. 做一个布尔变量reload_in_progresstrue当你开始从网上提取数据时将其设置为,false当所有缩略图都准备好时将其设置为。'reload' 点击处理程序应该在reload_in_progressis时忽略点击true

  3. 向用户展示一些国王progress bar,所以(s)他知道它已经重新加载并且不会reload再次推送。

  4. 几乎忘记了,永远不要更新“实时”显示给用户的数据,这会导致美妙的情况,当用户点击项目时它正在改变并做一些与他预期完全不同的事情。长时间更新应该将其数据保留给自己,并且只有在一切准备就绪时才快速将旧数据交换为新数据。

于 2012-04-21T17:23:55.163 回答
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调用都将发生在主线程上。我建议的最后一件事是更改您的 loadThumbs 任务,以便能够通过检查 isCancelled() 来尽快停止工作,只要这样做是有意义的。

于 2012-04-21T17:32:08.783 回答