最初の問題:
FragmentLists
カスタマイズされた内で複数を使用するアプリケーションに取り組んでいますFragmentStatePagerAdapter
。そのようなフラグメントの潜在的にかなりの数が20から40の間である可能性があります。- 各フラグメントは、各アイテムにテキストまたは画像を含めることができるリストです。
- 画像はWebから非同期でアップロードし、一時メモリキャッシュにキャッシュする必要があります。また、利用可能な場合はSDにもキャッシュする必要があります。
- フラグメントが画面から消えたら、アップロードと現在のアクティビティをキャンセルする必要があります(一時停止ではありません)
私の最初の実装は、Googleのよく知られたイメージローダーコードに従いました。そのコードに関する私の問題は、基本的にAsyncTask
画像ごとに1つのインスタンスを作成することです。私の場合、これはアプリを本当に速く殺します。
私はv4互換性パッケージを使用しているので、拡張するカスタムローダーを使用AsyncTaskLoader
すると、スレッドプールが内部的に実装されるため、役立つと思いました。ただし、このコードを複数回実行すると、次の呼び出しごとに前の呼び出しが中断されます。私のListView#getView
方法でこれを持っているとしましょう:
getSupportLoaderManager().restartLoader(0, args, listener);
このメソッドは、表示される各リストアイテムのループで実行されます。そして、私が述べたように、次の各呼び出しは前の呼び出しを終了します。または、少なくともそれはLogCatに基づいて起こることです
11-03 13:33:34.910: V/LoaderManager(14313): restartLoader in LoaderManager: args=Bundle[{URL=http://blah-blah/pm.png}]
11-03 13:33:34.920: V/LoaderManager(14313): Removing pending loader: LoaderInfo{405d44c0 #2147483647 : ImageLoader{405118a8}}
11-03 13:33:34.920: V/LoaderManager(14313): Destroying: LoaderInfo{405d44c0 #2147483647 : ImageLoader{405118a8}}
11-03 13:33:34.920: V/LoaderManager(14313): Enqueuing as new pending loader
それから、各ローダーに一意のIDを与えることで問題が解決するかもしれないと思いましたが、違いはないようです。その結果、私は一見ランダムな画像になってしまい、アプリは必要なものの1/4でもロードされません。
質問
- 私がやりたいことをするためにローダーを修正する方法は何でしょうか(そして方法はありますか?)
- そうでない場合、プールを作成するための良い方法は何
AsyncTask
ですか?おそらくそれの実装が機能していますか?
コードのアイデアを与えるために、実際のダウンロード/保存ロジックが別のImageManagerクラスにあるローダーの簡略版をここに示します。
public class ImageLoader extends AsyncTaskLoader<TaggedDrawable> {
private static final String TAG = ImageLoader.class.getName();
/** Wrapper around BitmapDrawable that adds String field to id the drawable */
TaggedDrawable img;
private final String url;
private final File cacheDir;
private final HttpClient client;
/**
* @param context
*/
public ImageLoader(final Context context, final String url, final File cacheDir, final HttpClient client) {
super(context);
this.url = url;
this.cacheDir = cacheDir;
this.client = client;
}
@Override
public TaggedDrawable loadInBackground() {
Bitmap b = null;
// first attempt to load file from SD
final File f = new File(this.cacheDir, ImageManager.getNameFromUrl(url));
if (f.exists()) {
b = BitmapFactory.decodeFile(f.getPath());
} else {
b = ImageManager.downloadBitmap(url, client);
if (b != null) {
ImageManager.saveToSD(url, cacheDir, b);
}
}
return new TaggedDrawable(url, b);
}
@Override
protected void onStartLoading() {
if (this.img != null) {
// If we currently have a result available, deliver it immediately.
deliverResult(this.img);
} else {
forceLoad();
}
}
@Override
public void deliverResult(final TaggedDrawable img) {
this.img = img;
if (isStarted()) {
// If the Loader is currently started, we can immediately deliver its results.
super.deliverResult(img);
}
}
@Override
protected void onStopLoading() {
// Attempt to cancel the current load task if possible.
cancelLoad();
}
@Override
protected void onReset() {
super.onReset();
// Ensure the loader is stopped
onStopLoading();
// At this point we can release the resources associated with 'apps'
// if needed.
if (this.img != null) {
this.img = null;
}
}
}