我很难实现延迟加载列表。我知道,关于类似问题的帖子数不胜数,但在评判之前请先看一下我的问题。
目标:加载SD卡上存在的位图缩略图,但不阻止主(UI)线程,因此列表会顺畅滚动。
来源: 我试过的基础是这两个帖子:
到目前为止我的尝试:
我试图实现一个类,它会加载和缓存(我不知道,如果它是适当的表达式)缩略图。它看起来像这样(我尽量不发布代码墙,所以我削减了不重要的部分):
public class ThumbnailContainer
{
//this will store the thumbnails
private final HashMap<File, SoftReference<Bitmap>> data;
//this Handler class will update the ui, when we got the thumb from a thread
private static final class BitmapHandler extends Handler
{
private final WeakReference<ImageView> image;
public BitmapHandler(ImageView image)
{this.image = new WeakReference<ImageView>(image);}
@Override
public void handleMessage(Message msg)
{
if(image.get()!=null)
image.get().setImageBitmap((Bitmap) msg.obj);
}
}
public ThumbnailContainer(Context context)
{
data = new HashMap<File, SoftReference<Bitmap>>();
}
//this will set the Bitmap to the ImageView (load on a thread if required)
public void setBitmapOnThread(final File file, final ImageView view)
{
//contains will return true, if the data map contains the file key
//and the SoftReference is still vaild.
if (contains(file))
{
view.setImageBitmap(data.get(file).get());
return;
}
else
{
final Handler handler = new BitmapHandler(view);
final Thread thread = new Thread()
{
@Override
public void run()
{
Bitmap bitmap = getMeasuredBitmap(file);
Message msg = handler.obtainMessage(0, bitmap);
handler.sendMessage(msg);
}
};
thread.start();
}
}
// load the Bitmap if it isn't already, scales it down, and recycles the original
private Bitmap getMeasuredBitmap(File file)
{
if (contains(file))
return data.get(file).get();
else
{
Bitmap bitmap = BitmapFactory.decodeFile(file.getAbsolutePath());
/*counting the scale of the new Bitmap, i cut the detail*/
Bitmap measured = Bitmap.createScaledBitmap(bitmap, w, h, false);
bitmap.recycle();
data.put(file, new SoftReference<Bitmap>(measured));
return measured;
}
}
//returns true, if the map contains this file, and the reference is still valid
private boolean contains(File file)
{
if (data.containsKey(file))
{
if (data.get(file).get() != null) return true;
else return false;
}
return false;
}
}
结果:我仍然得到一个非常滞后的列表滚动。这就像我甚至没有添加线程解决方案,只是在listadapters getView()
方法中加载了缩略图。我尝试将Threads
优先级(请参阅setBitmapOnThread()
)设置为LOW
,当我这样做时,滚动通常是平滑的,我可以看到缩略图加载,但是当我滚动时真快,然后我的内存耗尽。我认为这是因为启动了太多线程,而且无法完成。
我的问题:你们在这里看到一个明显的错误吗?
如果没有,那么坚持使用低优先级线程解决方案是否明智?如果是这样,那么是否有办法将线程数限制为固定数字(如5-6),如果达到最大线程数,则在开始新数据之前停止并加入未完成的数字?我读过ThreadPools,但我从来没用过。
我真的很感激任何帮助!
答案 0 :(得分:1)
我会像你一样停止使用Thread并使用AsyncTask。使用此任务从磁盘获取文件并将其放在缓存中(如果不存在)。将缓存的值返回到适配器中的ImageView。
因此,在您的适配器中将ImageView传递给AsyncTask。让任务完成工作。