この質問をする前に、次のものを検索して読みました: ListView Android での画像の遅延読み込み - ListView への画像の遅延読み込みに関する問題
私の問題は、私が持っていることですListView
。
- 各行には が含まれており
ImageView
、そのコンテンツはインターネットからロードされます - 各行のビューは、ApiDemo の List14 のようにリサイクルされます
最終的に欲しいもの:
- ユーザーがスクロールしたときにのみ、画像を遅延して読み込みます
- 応答性を維持するために、異なるスレッドに画像をロードします
私の現在のアプローチ:
- アダプターの
getView()
メソッドでは、他の子ビューをセットアップするのとは別に、インターネットからビットマップを読み込む新しいスレッドを起動します。その読み込みスレッドが終了すると、Bitmap
に設定される が返されます (またはImageView
を使用してこれを行います)。AsyncTask
Handler
- 私は s をリサイクルするので
ImageView
、最初に でビューを設定しBitmap#1
、後でBitmap#2
ユーザーが下にスクロールしたときに に設定したい場合があります。Bitmap#1
読み込みよりも時間がかかる場合がBitmap#2
あるため、ビューが上書きBitmap#2
される可能性があります。WeakHashMap
そのビューに最後Bitmap
に設定したいものを記憶する を維持することで、これを解決します。
以下は、私の現在のアプローチの擬似コードです。わかりやすくするために、キャッシングなどの他の詳細は省略しました。
public class ImageLoader {
// keeps track of the last Bitmap we want to set for this ImageView
private static final WeakHashMap<ImageView, AsyncTask> assignments
= new WeakHashMap<ImageView, AsyncTask>();
/** Asynchronously sets an ImageView to some Bitmap loaded from the internet */
public static void setImageAsync(final ImageView imageView, final String imageUrl) {
// cancel whatever previous task
AsyncTask oldTask = assignments.get(imageView);
if (oldTask != null) {
oldTask.cancel(true);
}
// prepare to launch a new task to load this new image
AsyncTask<String, Integer, Bitmap> newTask = new AsyncTask<String, Integer, Bitmap>() {
protected void onPreExecute() {
// set ImageView to some "loading..." image
}
protected Bitmap doInBackground(String... urls) {
return loadFromInternet(imageUrl);
}
protected void onPostExecute(Bitmap bitmap) {
// set Bitmap if successfully loaded, or an "error" image
if (bitmap != null) {
imageView.setImageBitmap(bitmap);
} else {
imageView.setImageResource(R.drawable.error);
}
}
};
newTask.execute();
// mark this as the latest Bitmap we want to set for this ImageView
assignments.put(imageView, newTask);
}
/** returns (Bitmap on success | null on error) */
private Bitmap loadFromInternet(String imageUrl) {}
}
まだ問題があります: 一部の画像がまだロードされている間にアクティビティが破棄された場合はどうなりますか?
- アクティビティが既に破棄されているときに、読み込みスレッドが後で ImageView にコールバックするリスクはありますか?
- さらに、
AsyncTask
下にいくつかのグローバルスレッドプールがあるため、長いタスクが不要になったときにキャンセルされない場合、ユーザーが表示
しないものをロードするのに時間を無駄にする可能性があります. このことをグローバルに保持するという私の現在の設計はあまりにも醜く、最終的には私の理解を超えたリークが発生する可能性があります.ImageLoader
このようなシングルトンを作成する代わりに 、実際ImageLoader
に異なる の個別のオブジェクトを作成しActivities
、Activity
が破棄されると、そのすべてAsyncTask
がキャンセルされることを考えています。これはあまりにも厄介ですか?
とにかく、Androidでこれを行う安全で標準的な方法があるのだろうか. さらに、私はiPhoneを知りませんが、同様の問題があり、この種のタスクを行う標準的な方法はありますか?
どうもありがとう。