代码之家  ›  专栏  ›  技术社区  ›  codeScriber

许多异步任务产生时出现异步任务性能问题。

  •  2
  • codeScriber  · 技术社区  · 14 年前

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

    我又想到用 AsyncTask 就像很多人在论坛上的建议一样。但有一个缺点。我看到很多用途 new MyTask().execute(urls); 如果我想开始加载并停止按需加载图像,这会出现一个问题。 如果我使用每个映像的异步任务,那么我需要为每个映像创建新的异步任务,这是许多“新”任务,我可以使用一个池,但是如果太多的异步任务被卡住,我仍然会创建大约150-200个asyc任务,太多的任务让我觉得……

    你们觉得怎么样?我认为线程在这里可以做得更好:

    1. 继续奔跑直到死亡
    2. 尝试从队列中获取作业,如果不是作业,请等待。
    3. 如果作业可用,则获取它并开始处理。
    4. 每个请求都是单独、连续地处理的,并且会阻塞线程。
    5. 有一次用“2”继续。
    6. 适配器使用 startLoadingImage() 对于需要显示的视图,将创建新作业并在等待锁上调用通知。

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

    2 回复  |  直到 10 年前
        1
  •  2
  •   Kevin Gaudin    14 年前

    我实现了这样的功能:

    /** 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

        2
  •  1
  •   Konstantin Burov    14 年前

    我认为你在做过早的优化。只要以尽可能快的方式实现您所需要的,您以后总是可以改进实现。另外,为什么您需要同时启动200个异步任务?我不认为你会在一个屏幕上显示所有的图像(在ListView的情况下,为什么加载所有的图像,即使用户永远无法滚动到列表的末尾?).