是否存在Android AsyncTaskQueue或类似产品?

是否存在Android AsyncTaskQueue或类似产品?,android,Android,我在某个地方读到(并观察到)启动线程很慢。我一直认为AsyncTask创建并重用了一个线程,因为它需要在UI线程内部启动 从ListAdapter的getView方法调用以下(匿名)代码以异步加载图像。它运行良好,直到用户快速移动列表,然后列表变为“” final File imageFile=新文件(getCacheDir().getPath()+“/img/”+p.image); image.setVisibility(View.GONE); view.findViewById(R.id.i

我在某个地方读到(并观察到)启动线程很慢。我一直认为AsyncTask创建并重用了一个线程,因为它需要在UI线程内部启动

从ListAdapter的getView方法调用以下(匿名)代码以异步加载图像。它运行良好,直到用户快速移动列表,然后列表变为“”

final File imageFile=新文件(getCacheDir().getPath()+“/img/”+p.image);
image.setVisibility(View.GONE);
view.findViewById(R.id.imageLoading).setVisibility(view.VISIBLE);
(新任务(){
@凌驾
受保护位图doInBackground(无效…参数){
试一试{
位图图像;
如果(!imageFile.exists()| | imageFile.length()==0){
image=BitmapFactory.decodeStream(新URL(
"http://example.com/images/"
+openStream());
image.compress(位图.CompressFormat.JPEG,85,
新的FileOutputStream(imageFile));
image.recycle();
}
image=BitmapFactory.decodeFile(imageFile.getPath(),
位图选项);
返回图像;
}捕获(格式错误){
//TODO自动生成的捕捉块
例如printStackTrace();
返回null;
}捕获(IOEX异常){
//TODO自动生成的捕捉块
例如printStackTrace();
返回null;
}
}
@凌驾
受保护的void onPostExecute(位图图像){
if(view.getTag()!=p)//该视图已被回收。
返回;
view.findViewById(R.id.imageLoading).setVisibility(
视图(已消失);
view.findViewById(R.id.image)
.setVisibility(View.VISIBLE);
((ImageView)view.findViewById(R.id.image))
.setImageBitmap(图像);
}
}).execute();

我认为基于队列的方法会更好,但我想知道是否有这样的方法,或者我是否应该尝试创建自己的实现。

示例中解释了该键

基本上,您必须跟踪listView的滚动状态并通知 当适配器准备好用visibile执行一些缓慢的操作时 项目

还要注意,将图像保存到磁盘是一个非常缓慢的过程。使用 基于内存的缓存策略将大大提高性能 应用程序

  • 我可以看到你们解码图像并将其压缩回磁盘,然后再解码。我想不是很有效。您可以将流从网络保存到磁盘,然后将其解压缩。这将是一次解压缩,而不是3次压缩/解压缩。将为您节省大量CPU处理时间

  • 我认为AsyncTask为多个图像创建了多个线程。因此,多个图像同时被压缩/解压缩,多个线程争夺CPU时间,不是很好。据我所知,AsyncTask使用线程池,所以它不会为每个映像启动新线程。但无论如何,同时使用多个线程并不太好。我同意排队会更有效。实现并不是很难自己创建。我使用自己的队列实现,对此我非常满意

  • 如果你有你自己的线程,我认为可以给它一个较低的优先级。这将使UI更具响应性

  • 您当然需要某种内存缓存,否则UI的速度就不够快。减压很慢。您不能存储所有图像,但只能存储最常用的图像。您可以使用SoftReference实现缓存。您可以使用inSampleSize选项使位图更小并占用更少的内存


  • 我制作了一个完整的LazyList示例,并发布了源代码,这可能也会有所帮助。

    您应该优化代码,以便在listview处于fling scroll模式时不会发出计算线程。“我一直认为AsyncTask创建并重用了一个线程,因为它需要在UI线程内部启动。”
    AsyncTask
    使用10个线程的线程池,从Android 1.6版开始。每个映像只会将映像保存到磁盘一次,并且这些映像会在整个应用程序中重复使用。我尝试了基于内存的缓存,但是虚拟机没有足够的内存来容纳我需要的所有东西。图像大小有这么大吗?你是否尝试将位图对象包装在软引用中?想想看,通过inInputShareable、InPurgable、inPreferredConfig和inSampleSize的组合,我可以将图像存储在哈希表中,而无需担心内存问题-它们在重用时只需重新加载自己。谢谢我再次解码它,以便可以使用inInputShareable/Inpurgable自动恢复内存。如果我只是使用网络拷贝,它将需要重新下载图像以重用它。是的,我认为Inpurgable是可以的。它保留缓存在内存中的位图。当内存不足时,位图将被删除并根据需要再次解析。事实上,我对软引用也是如此。
    final File imageFile = new File(getCacheDir().getPath() + "/img/" + p.image);
    image.setVisibility(View.GONE);
    view.findViewById(R.id.imageLoading).setVisibility(View.VISIBLE);
    (new AsyncTask<Void, Void, Bitmap>() {
        @Override
        protected Bitmap doInBackground(Void... params) {
            try {
                Bitmap image;
                if (!imageFile.exists() || imageFile.length() == 0) {
                    image = BitmapFactory.decodeStream(new URL(
                            "http://example.com/images/"
                                    + p.image).openStream());
                    image.compress(Bitmap.CompressFormat.JPEG, 85,
                            new FileOutputStream(imageFile));
                    image.recycle();
                }
                image = BitmapFactory.decodeFile(imageFile.getPath(),
                    bitmapOptions);
                return image;
            } catch (MalformedURLException ex) {
                // TODO Auto-generated catch block
                ex.printStackTrace();
                return null;
            } catch (IOException ex) {
                // TODO Auto-generated catch block
                ex.printStackTrace();
                return null;
            }
        }
    
        @Override
        protected void onPostExecute(Bitmap image) {
            if (view.getTag() != p) // The view was recycled.
                return;
                view.findViewById(R.id.imageLoading).setVisibility(
                    View.GONE);
            view.findViewById(R.id.image)
                    .setVisibility(View.VISIBLE);
            ((ImageView) view.findViewById(R.id.image))
                    .setImageBitmap(image);
        }
    }).execute();