Android-リストビューへの画像の遅延読み込みに関する問題
-
05-07-2019 - |
質問
これは非常に一般的なシナリオです。インターネットからダウンロードする必要がある画像をListViewに表示します。
今、ListViewに使用するArrayAdapterのカスタムサブクラスがあります。 ArrayAdapterのgetView()実装では、別のスレッドを生成して画像を読み込みます。ロードが完了すると、適切なImageViewを検索し、ImageView.setImageDrawable()で画像を設定します。したがって、私が使用した解決策は、次のようなものです: ListViewでの画像の遅延読み込み
私が抱えている問題は、ImageViewでsetImageDrawable()を呼び出すとすぐに、ListViewがリスト内の現在表示されているすべての行を何らかの方法で更新することです。これにより、一種の無限ループが発生します。
- getView()が呼び出されます
- 画像をロードするためにスレッドが生成されます
- 画像がロードされます。 setImageDrawable()はImageViewで呼び出されます
- ListViewは何らかの理由でそれを取得し、それ自体を更新します
- ListViewを更新するには、表示されている行ごとにgetView()が呼び出されるため、手順1に戻り、すべてが繰り返されます
つまり、「Android-ListViewで画像の遅延ロードを行うには」で提案されている解決策です。 (上記のリンクを参照)単に機能しません。表示されるように見えるかもしれませんが、バックグラウンドでは現在表示されている行を再読み込みし続けるため、非常に遅くなります。
以前に誰かがこれに遭遇したか、または解決策を持っていますか?
解決
リンクされたソリューションでは、 fetchDrawableOnThread()
は、ビューに正しいドローアブルがまだない場合にのみ呼び出す必要があります。
getDrawable()
がnullを返す場合、ビューにはドロアブルがありません。
スロットを再利用する場合は、さらに進んで状態を管理する必要があると思われます。ビューに、URLを格納するメンバー変数と、ロードされるかどうかを示すブール値がある場合、たとえば fetchDrawableOnThread()
を呼び出すかどうかを簡単に知ることができます。
ドロアブルの toString()
には、イメージのロード元のパスが詳細に記載されていると推測します。 (そうでない場合は、返されるドロアブルをサブクラス化して、そうすることができます)。この場合、上記のブール値を回避し、比較を行って正しいドローアブルか、置換を取得するかどうかを判断できます。
さらに、表示されている行のgetView()は、メモリの枯渇を防ぐために、表示されなくなった行を確実にアンロードする必要があります。巧妙な方法は、表示されなくなった画像をソフト参照に移動することです(したがって、メモリが必要なときにそれらはアンロードされます)。
他のヒント
次のリンクでコードを使用しました:別のstackoverflowの質問
iは、ビューのリサイクルの問題を解決するために小さな変更を加えました。アダプターで、イメージの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;
}
同じ問題が発生しました。
ほぼ2日間の大量のデバッグ/最適化と把握を試みた後、 setImageBitmap()
getView()が繰り返し呼び出される理由>並んで、汚い解決策を思いつきました:
1)リスト内のすべての画像に使用するカスタム ImageView
を拡張します
2)この ImageView
でメソッドを上書き
@Override
public void requestLayout()
{
return;
}
3)汚れていますが、私にとっては動作します
4)利益;)
ThumbnailAdapter を使用して、役立つパターン全体をまとめています。