7

これは非常に一般的なシナリオです。インターネットからダウンロードする必要がある画像を ListView に表示します。

現在、ListView に使用する ArrayAdapter のカスタム サブクラスがあります。ArrayAdapter の getView() 実装では、別のスレッドを生成して画像を読み込みます。ロードが完了すると、適切な ImageView が検索され、ImageView.setImageDrawable() で画像が設定されます。したがって、私が使用したソリューションは、次のようなものです: ListView での画像の遅延ロード

私が抱えている問題は、ImageView で setImageDrawable() を呼び出すとすぐに、ListView がリスト内の現在表示されているすべての行を何らかの形で更新することです! これにより、一種の無限ループが発生します。

  1. getView() が呼び出されます
  2. 画像をロードするためにスレッドが生成されます
  3. 画像が読み込まれます。setImageDrawable() は ImageView で呼び出されます
  4. ListView は何らかの理由でそれを取得し、それ自体を更新します
  5. ListView を更新するには、表示されている行ごとに getView() が呼び出されるため、手順 1 に戻り、すべてが繰り返されます。

私が見る限り、「Android - ListView で画像を遅延ロードするにはどうすればよいですか」(上記のリンクを参照) で提案されているソリューションは単に機能しません。そのように見えるかもしれませんが、バックグラウンドで現在表示されている行を再ロードし続けるため、非常に遅くなります。

誰かが以前にこれに遭遇したか、および/またはこれに対する解決策を持っていますか?

4

4 に答える 4

4

次のリンクのコードを使用しました:別のスタックオーバーフローの質問

リサイクルビューの問題を解決するために小さな変更を加えました。アダプターのイメージビューのタグに画像のURLを設定しました。次のコードには、リサイクルの問題を解決する私のソリューションが含まれています。

public void fetchDrawableOnThread(final String urlString, final ImageView imageView,Drawable drw) {

    imageView.setImageDrawable(drw);//drw is default image
    if (drawableMap.containsKey(urlString)) {
        if(imageView.getTag().toString().equals(urlString))
        {
            imageView.setImageBitmap(drawableMap.get(urlString));
            imageView.invalidate();
            return;
        }

    }

    final Handler handler = new Handler() {
        @Override
        public void handleMessage(Message message) {
            BitmapWrapper wrapper = (BitmapWrapper)message.obj;
            if(wrapper.imageurl.equals(imageView.getTag().toString()))
            {
                imageView.setImageBitmap((Bitmap)wrapper.bitmap);
                imageView.invalidate();
            }

        }
    };

    Thread thread = new Thread() {
        @Override
        public void run() {
            //TODO : set imageView to a "pending" image

            Bitmap drawable = fetchDrawable(urlString);
            BitmapWrapper wrapper = new BitmapWrapper();
            wrapper.bitmap = drawable;
            wrapper.imageurl = urlString;
            Message message = handler.obtainMessage(1, wrapper);
            handler.sendMessage(message);
        }
    };
    thread.start();
}


    public class BitmapWrapper
{
    public Bitmap bitmap;
    public String imageurl;
}
于 2011-03-23T20:58:15.567 に答える
4

同じ問題がありました。

ほぼ 2 日間の重いデバッグ/最適化と把握しようとした後、行でgetView()使用するときにすべてのビューに対して何度も呼び出される理由を理解しようとした後、私はsetImageBitmap()汚い解決策を思いつきました:

ImageView1)リスト内のすべての画像に使用するカスタムを拡張します

2)これImageViewでメソッドを上書きします

@Override
public void requestLayout()
{ 
  return; 
}

3) 汚いですが、私にとってはうまくいきます

4) 利益;)

于 2012-03-07T13:32:32.147 に答える
3

リンクされたソリューションでfetchDrawableOnThread()は、ビューに正しいドローアブルがまだない場合にのみ呼び出す必要があります。

getDrawable()nullを返す場合、ビューにはドローアブルがありません。

スロットを再利用している場合は、さらに進んで状態を管理する必要があると考えています。ビューにURLを格納するメンバー変数と、それがロードされているかどうかを示すブール値がある場合fetchDrawableOnThread()、たとえば、呼び出すかどうかを簡単に知ることができます。

ドローアブルtoString()は、画像がロードされたパスの詳細を示していると思います。(そうでない場合は、返されたドローアブルをサブクラス化して、そうすることができます)。この場合、上記で概説したブール値を回避し、比較を行って、それが適切なドローアブルであるかどうか、または置換をフェッチするかどうかを判断できます。

さらに、表示されている行のgetView()は、メモリの枯渇を防ぐために、表示されなくなった行がアンロードされるようにする必要があります。フィネスは、元のスレッドの別のポスターに記載されているように、表示されなくなった画像をソフト参照に移動することです(したがって、メモリが必要なときに画像がアンロードされます)。

于 2009-09-11T08:34:50.070 に答える
2

このパターン全体をまとめたThumbnailAdapterが役立つかもしれません。

于 2009-09-11T10:43:33.773 に答える