0

遅延読み込みリストを実装するのに本当に苦労しています。同様の問題に関する無数の投稿があることは知っていますが、判断する前に私の問題を見てください。

目標: SD カードに存在するビットマップのサムネイルをロードしますが、メイン (UI) スレッドをブロックしないため、リストがスムーズにスクロールします。

ソース:私が試したもののベースは、これらの2つの投稿でした:

これまでの私の試み

サムネイルをロードしてキャッシュするクラスを実装しようとしました(適切な式かどうかはわかりません)。これは次のようになります (私はコードの壁を投稿しないようにしているので、重要でない部分をカットしています):

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 について読みましたが、使用したことはありません。

私は本当に助けていただければ幸いです!

4

1 に答える 1

1

あなたのようにスレッドの使用をやめ、AsyncTask を使用します。このタスクを使用して、ディスクからファイルを取得し、キャッシュに配置します (存在しない場合)。キャッシュされた値をアダプタの ImageView に返します。

したがって、アダプタで ImageView を AsyncTask に渡します。タスクに仕事をさせましょう。

于 2012-09-10T19:52:13.943 に答える