2

我正在尝试为来自设备和网络的图像创建一个惰性图像加载器,用于ListView. 我正在考虑使用什么以及如何使用,一方面我可以使用一个线程来汇集我的请求(始终运行,我可以附加一个视图和一个适配器,它将为我处理图像加载),缓存我已经加载图像并在加载之前检查图像的可见性,这样我就不会做不必要的工作。

我有另一个想法使用AsyncTask论坛中的许多建议。不过有一个缺点。new MyTask().execute(urls); 如果我想开始加载和停止按需加载图像,我看到很多人使用这会出现问题。如果我对每个图像使用异步任务,那么我需要为每个图像创建新的异步任务,这是很多“新”任务,我可以使用一个池,但是如果太多异步任务被卡住,我仍然会创建大约 150- 200个asyc任务,对我来说太多了......

你们有什么感想?我认为一个线程在这里会做得更好:

  1. 继续跑直到被杀
  2. 尝试从队列中获取工作,如果没有工作,请等待。
  3. 如果有工作,请获取并开始处理。
  4. 每个请求都单独处理,串行并阻塞线程。
  5. 一旦确实继续使用“2”。
  6. startLoadingImage()适配器为需要显示的视图完成的每个入队都将创建一个新作业并在等待锁上调用通知。

如果我想要多个并行的 GET\POST 请求,我可以使用线程池优化此代码。此外,我正在缓存我已经下载\加载的图像,以便在下次访问时快速加载。这个想法是最小化 GC 和列表滞后。

4

2 回答 2

2

我实现了这样的东西:

/** Contains all the pending requests for thumbnails. */
private LinkedList<Uri> mPendingThumbnailRequests = new LinkedList<Uri>();

private ThumbnailGetter mThmGetter = null;
/**
 * Asynchronous process for retrieving thumbnails from Uris.
 */
private class ThumbnailGetter extends AsyncTask<Uri, Integer, Uri> {
    private final String LOG_TAG = ThumbnailGetter.class
            .getSimpleName();
    /** The Uri beeing processed */
    private Uri mUri = null;
    /*
     * (non-Javadoc)
     * 
     * @see android.os.AsyncTask#doInBackground(Params[])
     */
    @Override
    protected Uri doInBackground(Uri... uris) {
        // We process Uris one after another... so the Array contains
        // only one Uri.
        mUri = uris[0];
        // Let the ThumbnailLoader do the job.
        Uri result = ItemsLoader.getThumbnail(mContext, mUri);
        return result;
    }
    /*
     * (non-Javadoc)
     * 
     * @see android.os.AsyncTask#onPostExecute(java.lang.Object)
     */
    @Override
    protected void onPostExecute(Uri result) {
        super.onPostExecute(result);
        // Give the retrieved thumbnail to the adapter...
        mImageAdapter.updateThumbUri(mUri, result);
        // then process any other pending thumbnail request.
        if (!mPendingThumbnailRequests.isEmpty()) {
            mThmGetter = new ThumbnailGetter();
            mThmGetter.execute(mPendingThumbnailRequests.poll());
         }
     }
}

然后我添加 Uris 加载使用:

if (!mPendingThumbnailRequests.contains(imageUri)) {
    mPendingThumbnailRequests.offer(imageUri);
    if (mThmGetter == null
            || mThmGetter.getStatus() == AsyncTask.Status.FINISHED) {
        // If the previous instance of the thumbnail getter has
        // finished, start a new one.
        mHandler.sendEmptyMessage(MSG_SHOW_INDETERMINATE_PROGRESS);
        mThmGetter = new ThumbnailGetter();
        mThmGetter.execute(mPendingThumbnailRequests.poll());
    }
}

这甚至可以让您使用取消请求mPendingThumbnailRequests.remove()

完整的实现在这里: http ://code.google.com/p/emailalbum/source/browse/EmailAlbumAndroid/trunk/src/com/kg/emailalbum/mobile/creator/SelectPictures.java

于 2010-09-19T22:27:56.387 回答
1

我认为你正在做过早的优化。只需以尽可能最快的方式实施您需要的东西,之后您总是可以改进实施。另外,为什么您需要同时启动 200 个 AsyncTask?我认为您不会在一个屏幕上显示所有图像(如果是 ListView,为什么即使用户永远无法滚动到列表末尾,为什么还要加载所有图像?)。

于 2010-09-19T09:44:01.483 回答