Android 许多异步任务生成时的异步任务性能问题。
我正在尝试为Android 许多异步任务生成时的异步任务性能问题。,android,listview,android-asynctask,lazy-loading,Android,Listview,Android Asynctask,Lazy Loading,我正在尝试为列表视图的设备和web上的图像创建一个惰性图像加载程序。 我正在考虑使用什么以及如何使用一个线程来汇集我的请求(总是在运行,我可以附加一个视图和一个适配器,它将为我处理图像加载),缓存我已经加载的图像,并在加载之前检查图像的可见性,这样我就不会做不必要的工作 我有另一个想法,使用AsyncTask,就像论坛上许多人建议的那样。不过有一个缺点。我看到很多人使用newmytask().execute(URL)如果我想开始加载和停止按需加载图像,这会出现问题。 如果我使用每个映像的异步任务
列表视图
的设备和web上的图像创建一个惰性图像加载程序。
我正在考虑使用什么以及如何使用一个线程来汇集我的请求(总是在运行,我可以附加一个视图和一个适配器,它将为我处理图像加载),缓存我已经加载的图像,并在加载之前检查图像的可见性,这样我就不会做不必要的工作
我有另一个想法,使用AsyncTask
,就像论坛上许多人建议的那样。不过有一个缺点。我看到很多人使用newmytask().execute(URL)代码>如果我想开始加载和停止按需加载图像,这会出现问题。
如果我使用每个映像的异步任务,那么我需要为每个映像创建新的异步任务,这是一个非常“新”的任务,我可以使用一个池,但是如果有太多的异步任务被卡住,我仍然会创建大约150-200个asyc任务,太多太多了,太多了
你们觉得怎么样?我认为线程在这里会做得更好:
一直跑到死
尝试从队列中获取作业,如果不是作业,请稍候
如果作业可用,则获取它并开始处理
每个请求都单独、连续地处理,并阻塞线程
Once does继续使用“2”
适配器对需要显示的视图使用startLoadingImage()
进行的每个排队将创建一个新作业,并在等待锁上调用notify
如果我需要几个并行的GET\POST请求,我可以使用一个线程池来优化这段代码。
此外,我正在缓存已下载\加载的图像,以便下次访问时快速加载。我们的想法是尽量减少GC和列表滞后。我认为您正在进行过早的优化。只要以最快的方式实现您所需要的,您就可以在以后改进实现。还有,为什么您需要同时启动200个异步任务?我不认为您将在一个屏幕上显示所有图像(在ListView的情况下,为什么要加载所有图像,即使用户永远无法滚动到列表的末尾?) 我实现了如下内容:
/** 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());
}
}
}
这甚至允许您使用mPendingThumbnailRequests.remove()取消请求
全面实施如下:
否,这是用户可以滚动到最后的点,所有图像都将预加载一个默认图像,如“等待加载”等,一旦加载图像,视图将得到通知,并且图像将放置在正确的视图中。一旦它被缓存,加载的响应时间就很快,所以不需要以异步方式进行。关于200个异步任务,这只是我为什么不使用它的一个例子……我这样做了,现在我得到了java.util.concurrent.RejectedExecutionException,如果我滚动太快,并且在正常滚动时任务的完成顺序混乱。这可能是最容易做到的。首先,这个代码绝对是好的,但是如果我考虑一个图像列表,这些图片以未知的速度和批次加载(因为用户可以按他喜欢的快或慢的速度滚动)。你会创建相对较多的AyncTasks,而你自己的线程只创建一次,然后一直休眠到你将一个新对象加入队列为止。的确,对他来说,内存会多一点,但如果你使用自己的池,避免在运行中创建新对象,那么它与GC相反是多余的()当我们重用现有的异步任务(如果有的话)时,不会创建很多异步任务。实际上,当用户开始滚动并且有一些缩略图需要检索时,它会重新创建一个新的缩略图。。。但这只是滚动开始时的一个分配问题。我从来都不喜欢休眠线程,更担心那些线程永远不会停止或被复制。嘿,我刚刚发现你是对的,我为每个Uri创建了一个新的AsyncTask。。。我会努力的。谢谢你给我看这个您不需要同步访问mPendingThumbnailRequests
?否则,某些异步任务可能会执行两次(或零次,具体取决于设置了AsyncTask.Status.FINISHED
)。
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());
}
}