この記事では、画像を非同期にロードし、キャッシュして表示するために開発した(だけでなく)ツールについて説明します。 開発のこの段階では、インターネットまたはファイルシステムから画像をImageViewにアップロードする必要があるあらゆる場所で使用できます。 必要なのは、
イメージの
URL (ファイルシステムの場合は“ file://”で始まる)と、ダウンロードしたイメージを配置する必要がある
ImageView自体です。
ImageLoaderのユニバーサルの機能の詳細については、以下をお読みください。
すべてが1つのプロジェクトで始まり、そこに私は参加する機会がありました:ニュースのリストの表示を実装する必要があり、そしてもちろん、リストアイテムに写真を表示することについての質問が生じました。 写真はインターネットからダウンロードされたため、非同期の読み込み、表示、キャッシュを実装する必要がありました。 ネット上で簡単に検索した結果、
この問題に対する次のほぼ準備ができた解決策が見つかりました 。 実装された
LazyImageLoaderは、インターネットから非同期に画像をダウンロードし、ファイルシステムにキャッシュし、メモリに保存しました。 メモリ内の保存方法は、弱いリンクのない単純なHashMapでした。その結果、リストをスクロールする特定の段階で
OutOfMemoryErrorが飛び出し始めました(そして、リストもたくさんありました)。 HashMapは
WeakValueHashMapに置き換えられ、その後、メモリ制限のあるMapの独自の実装に置き換えられ、徐々にこのLazyImageLoaderに基づいて、独自の
ImageLoaderが独自のチップとトリックで成長し始めました。 リストだけでなくギャラリーでも写真を表示したり、簡単な「1回限りの」表示に使用できます。 このImageLoaderは、後に他の2つのプロジェクトで再利用され、その実行可能性が確認されました。 既存のコードを大幅にリファクタリングし、容認できる美しさをもたらしたので、
ソースコードをGitHubにアップロードしましたが、ここでツールがさらに最適化され、柔軟性とカスタマイズが向上します。 キャッシングはどうですか?
キャッシングは次のように分かれています。
- インメモリーキャッシング
- ファイルシステムキャッシング(電話メモリまたはSDカード)
メモリキャッシュは、値に弱いリンクがあるHashMap <String、Bitmap>です。 どのように「弱」(ソフト、弱、ファントム)を決定するか:
public abstract class Cache<K, V> { protected final Map<K, Reference<V>> softMap = new HashMap<K, Reference<V>>(); public V get(K key) { if (softMap.containsKey(key)) { Reference<V> reference = softMap.get(key); return reference.get(); } else { return null; } } public void put(K key, V value) { softMap.put(key, createReference(value)); } public void clear() { softMap.clear(); } protected abstract Reference<V> createReference(V value); }
現在のバージョンでは、サイズを制御するビットマップキャッシュを使用しています。 これは、
ソフトマップからビットマップへの「強力な」リンク
が保存された追加の「ハード」リストを導入することで実装されました。 キャッシュサイズが許容限度を超えると、「最も古い」オブジェクトが「ハードリスト」から削除されるため、強力なリンクが失われます。 弱いリンクはまだ
softMapに格納されてい
ますが、ビットマップは既に完全にガベージコレクターの
手に委ねられていますファイルシステムにキャッシュする
場合 、ファイルは
imageUrl.hashCode()と呼ばれ、同じ原理でキャッシュが検索されます。 ImageLoaderのメソッドは次のとおりです。
void displayImage(String imageUrl, ImageView imageView, DisplayImageOptions options, ImageLoadingListener listener)
パラメータ
imageUrlと
imageViewは 、私が思うに、
問題を
引き起こすことはないと思います
DisplayImageOptionsクラスは、画像の読み込み、キャッシュ、表示のプロセスを設定するように設計されています。 これを使用して、以下を指定できます。
- 実際の画像の読み込み中にImageViewでスタブ画像を表示する必要があるかどうか、およびどのスタブを表示するか。
- ダウンロードした画像をメモリにキャッシュするかどうか。
- ダウンロードしたイメージをファイルシステムにキャッシュする必要がありますか。
ImageLoadingListenerインターフェイスを使用すると、画像の読み込みプロセスを「聞く」ことができます。
public interface ImageLoadingListener { void onLoadingStarted(); void onLoadingComplete(); }
ただし、現在の画像がメモリ内のキャッシュにある場合、
リスナーはイベントをスローしません。 UIストリームでイベントがスローされるため、
リスナーで静かな魂を使ってUIに触れることができるので、
ImageLoaderの使用例 :
ImageLoader imageLoader = ImageLoader.getInstance(context); DisplayImageOptions options = new DisplayImageOptions.Builder() .showStubImage(R.drawable.stub_image) .cacheInMemory() .cacheOnDisc() .build(); imageLoader.displayImage(imageUrl, imageView, options, new ImageLoadingListener() { @Override public void onLoadingStarted() { spinner.show(); } @Override public void onLoadingComplete() { spinner.hide(); } });
ImageLoaderの動作のメカニズムについてはあまり説明しません。 私はいくつかのことだけを言います:
- 画像を表示するタスクはキューに配置されます。画像が既にファイルシステムのキャッシュにある場合、タスクはキューの先頭に移動し、そうでない場合は最後に移動します。 タスクはキューの先頭から実行されるため、主にキャッシュされた画像が表示されます。 ( UPD :マルチスレッドイメージ表示メカニズムの導入後、このロジックは廃止されました。現在、キャッシュイメージと非キャッシュイメージのロードに2つの異なるスレッドプールが関与しています。キャッシュイメージ、シングルスレッド、その他、マルチスレッド)
- フルサイズのビットマップはメモリ内のキャッシュに保存されませんが、ImageViewでの表示に必要なサイズ以上ではありません。 このサイズは、属性maxWidthおよびmaxHeight 、 layout_width 、およびlayout_height 、デバイスの画面サイズに基づいて計算されます(元の画像のサイズは、画像のデコードに関する推奨事項に従って2のべき乗で縮小されます)。
- なぜなら まず、ImageLoaderはリストに画像を表示することを目的としていますが、原則として、Viewを再利用することをお勧めします。ImageLoaderは、独自のキーを使用して、タグImageViewに画像のロードされたURLを保存することにより、このような状況も監視します
もう一度、
GitHubの
ソースへのリンクを提供し
ますが、この
ImageLoaderがお役に立てば幸いです。
UPD(2011年12月19日):ツールにいくつかの重要な変更が加えられました。それらの詳細とプロジェクト全体については、
こちらをご覧ください 。
UPD(2012年2月23日):多くの変更と改善が行われました(マルチスレッド、外部構成を含む)。 ただし、メインAPIは基本的に同じです。 これで、ツールがjarとして使用可能になりました。 バージョン管理が導入されました。
UPD(2012年3月11日):ライブラリの使用に関する詳細なガイド
を書きました。