遅延読み込みリストを実装するのに本当に苦労しています。同様の問題に関する無数の投稿があることは知っていますが、判断する前に私の問題を見てください。
目標: SD カードに存在するビットマップのサムネイルをロードしますが、メイン (UI) スレッドをブロックしないため、リストがスムーズにスクロールします。
ソース:私が試したもののベースは、これらの2つの投稿でした:
- ListView は非常に遅い - Android (ViewHolder のアイデア)
- ListView での画像の遅延ロード (スレッド化のアイデア)
これまでの私の試み:
サムネイルをロードしてキャッシュするクラスを実装しようとしました(適切な式かどうかはわかりません)。これは次のようになります (私はコードの壁を投稿しないようにしているので、重要でない部分をカットしています):
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;
}
}
結果: リストのスクロールが非常に遅くなります。スレッドソリューションを追加していないようで、listadaptersgetView()
メソッドにサムネイルをロードしただけです。Threads
優先度 ( を参照setBitmapOnThread()
) をに設定しようとしましLOW
たが、これを行うと、通常はスクロールがスムーズになり、サムネイルが読み込まれているのがわかりますが、非常に速くスクロールすると、メモリが不足します。これは、開始されたスレッドが多すぎて終了できなかったためだと思います。
私の質問: ここに明らかなエラーがありますか?
そうでない場合は、優先順位の低いスレッド ソリューションに固執するのが賢明でしょうか? もしそうなら、最大スレッド数に達した場合、スレッド数を固定数 (5-6 など) に制限し、新しいスレッドを開始する前に未完成のスレッドを停止して参加する方法はありますか? ThreadPools について読みましたが、使用したことはありません。
私は本当に助けていただければ幸いです!