AndroidのListViewに画像を遅延ロードする方法



How Lazily Load Images Listview Android



使用しています ListView これらの画像に関連するいくつかの画像とキャプションを表示します。インターネットから画像を取得しています。テキストを表示するときにUIがロックされないように、画像をダウンロードするときにUIがロックされないように、画像の読み込みを遅らせる方法はありますか?

画像の総数は固定されていません。




#1階

見てください シャッターバグ 、これはApplidiumの軽量SDWebImage(iOS上の優れたライブラリ)に移植されたものです アンドロイド 。非同期キャッシュをサポートし、保存に失敗しました URL 、並行性を適切に処理し、便利なサブクラスが含まれています。

プルリクエスト(およびバグレポート)も大歓迎です!




#2階

この問題はAndroid開発者の間で非常に人気があり、この問題を解決すると主張するそのようなライブラリはたくさんあると思いますが、解決できるライブラリはごくわずかのようです。 AQuery これはそのようなライブラリですが、あらゆる点でほとんどのライブラリよりも優れており、試す価値があります。


#3階

私はこのAndroidトレーニングを受けましたが、メインインターフェイスをブロックすることなく画像をダウンロードするのに適していると思います。また、多くの画像をキャッシュおよびスクロールする手順も処理します。 大きなビットマップを効率的にロードする

zqoX2.jpg




#4階

ノボダも素晴らしいです レイジー画像読み込みライブラリ 多くのアプリケーション(Songkick、Podio、SecretDJ、ImageSearchなど)はライブラリを使用します。

彼らの図書館ホスティング ここに Githubでは、非常にアクティブです 課題追跡システム 同じように。彼らのプロジェクトも非常に活発で、この回答を書いている時点で300を超える提出があります。


#5階

さて、インターネットから画像をロードする時間のための多くの解決策があります。ライブラリを使用することもできます Android-クエリ 。それはあなたにすべての必要な活動を提供します。何をしようとしているのかを確認し、ライブラリのWikiページを読んでください。そして、画像の読み込みの制限を解決しました。

これは私のコードです:

@Override public View getView(int position, View convertView, ViewGroup parent) { View v = convertView if (v == null) { LayoutInflater vi = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE) v = vi.inflate(R.layout.row, null) } ImageView imageview = (ImageView) v.findViewById(R.id.icon) AQuery aq = new AQuery(convertView) String imageUrl = 'http://www.vikispot.com/z/images/vikispot/android-w.png' aq.id(imageview).progress(this).image(imageUrl, true, true, 0, 0, new BitmapAjaxCallback() { @Override public void callback(String url, ImageView iv, Bitmap bm, AjaxStatus status) { iv.setImageBitmap(bm) } )) return v }

遅延読み込みの問題を解決するはずです。


#6階

私のチェック LazyList フォーク。基本的に、ImageViewの呼び出しを遅らせることで、LazyListを改善し、次の2つのメソッドを作成しました。

  1. 「画像を読み込んでいます...」のようなものを配置する必要がある場合
  2. ダウンロードした画像を表示する必要がある場合。

このオブジェクトに実装することによって シングルトン 、ImageLoaderも改善しました。


#7階

DroidParts ImageFetcher 開始するにはゼロ構成が必要です。

  • ディスクとメモリを使用する 最近 少なくとも 使用する (LRU)キャッシュ。
  • 画像を効率的にデコードします。
  • バックグラウンドスレッドでビットマップを変更するためのサポート。
  • シンプルなフェードインとフェードアウトの効果があります。
  • 画像の読み込みの進行状況のコールバックがあります。

クローンを作成するには DroidPartsGram 例えば:

画像


#8階

新しいAndroidVolleyライブラリを使用していますcom.android.volley.toolbox.NetworkImageView NetworkImageView、それは非常にうまく機能しているようです。明らかに、これはと同じです グーグルプレイ 他の新しいGoogleアプリケーションで使用されているのと同じビュー。それは間違いなく試してみる価値があります。


#9階

public class ImageDownloader { Map imageCache public ImageDownloader() { imageCache = new HashMap() } // download function public void download(String url, ImageView imageView) { if (cancelPotentialDownload(url, imageView)) { // Caching code right here String filename = String.valueOf(url.hashCode()) File f = new File(getCacheDirectory(imageView.getContext()), filename) // Is the bitmap in our memory cache? Bitmap bitmap = null bitmap = (Bitmap) imageCache.get(f.getPath()) if (bitmap == null) { bitmap = BitmapFactory.decodeFile(f.getPath()) if (bitmap != null) { imageCache.put(f.getPath(), bitmap) } } // No? download it if (bitmap == null) { try { BitmapDownloaderTask task = new BitmapDownloaderTask( imageView) DownloadedDrawable downloadedDrawable = new DownloadedDrawable( task) imageView.setImageDrawable(downloadedDrawable) task.execute(url) } catch (Exception e) { Log.e('Error==>', e.toString()) } } else { // Yes? set the image imageView.setImageBitmap(bitmap) } } } // cancel a download (internal only) private static boolean cancelPotentialDownload(String url, ImageView imageView) { BitmapDownloaderTask bitmapDownloaderTask = getBitmapDownloaderTask(imageView) if (bitmapDownloaderTask != null) { String bitmapUrl = bitmapDownloaderTask.url if ((bitmapUrl == null) || (!bitmapUrl.equals(url))) { bitmapDownloaderTask.cancel(true) } else { // The same URL is already being downloaded. return false } } return true } // gets an existing download if one exists for the imageview private static BitmapDownloaderTask getBitmapDownloaderTask( ImageView imageView) { if (imageView != null) { Drawable drawable = imageView.getDrawable() if (drawable instanceof DownloadedDrawable) { DownloadedDrawable downloadedDrawable = (DownloadedDrawable) drawable return downloadedDrawable.getBitmapDownloaderTask() } } return null } // our caching functions // Find the dir to save cached images private static File getCacheDirectory(Context context) { String sdState = android.os.Environment.getExternalStorageState() File cacheDir if (sdState.equals(android.os.Environment.MEDIA_MOUNTED)) { File sdDir = android.os.Environment.getExternalStorageDirectory() // TODO : Change your diretcory here cacheDir = new File(sdDir, 'data/ToDo/images') } else cacheDir = context.getCacheDir() if (!cacheDir.exists()) cacheDir.mkdirs() return cacheDir } private void writeFile(Bitmap bmp, File f) { FileOutputStream out = null try { out = new FileOutputStream(f) bmp.compress(Bitmap.CompressFormat.PNG, 80, out) } catch (Exception e) { e.printStackTrace() } finally { try { if (out != null) out.close() } catch (Exception ex) { } } } // download asynctask public class BitmapDownloaderTask extends AsyncTask { private String url private final WeakReference imageViewReference public BitmapDownloaderTask(ImageView imageView) { imageViewReference = new WeakReference(imageView) } @Override // Actual download method, run in the task thread protected Bitmap doInBackground(String... params) { // params comes from the execute() call: params[0] is the url. url = (String) params[0] return downloadBitmap(params[0]) } @Override // Once the image is downloaded, associates it to the imageView protected void onPostExecute(Bitmap bitmap) { if (isCancelled()) { bitmap = null } if (imageViewReference != null) { ImageView imageView = imageViewReference.get() BitmapDownloaderTask bitmapDownloaderTask = getBitmapDownloaderTask(imageView) // Change bitmap only if this process is still associated with // it if (this == bitmapDownloaderTask) { imageView.setImageBitmap(bitmap) // cache the image String filename = String.valueOf(url.hashCode()) File f = new File( getCacheDirectory(imageView.getContext()), filename) imageCache.put(f.getPath(), bitmap) writeFile(bitmap, f) } } } } static class DownloadedDrawable extends ColorDrawable { private final WeakReference bitmapDownloaderTaskReference public DownloadedDrawable(BitmapDownloaderTask bitmapDownloaderTask) { super(Color.WHITE) bitmapDownloaderTaskReference = new WeakReference( bitmapDownloaderTask) } public BitmapDownloaderTask getBitmapDownloaderTask() { return bitmapDownloaderTaskReference.get() } } // the actual download code static Bitmap downloadBitmap(String url) { HttpParams params = new BasicHttpParams() params.setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1) HttpClient client = new DefaultHttpClient(params) final HttpGet getRequest = new HttpGet(url) try { HttpResponse response = client.execute(getRequest) final int statusCode = response.getStatusLine().getStatusCode() if (statusCode != HttpStatus.SC_OK) { Log.w('ImageDownloader', 'Error ' + statusCode + ' while retrieving bitmap from ' + url) return null } final HttpEntity entity = response.getEntity() if (entity != null) { InputStream inputStream = null try { inputStream = entity.getContent() final Bitmap bitmap = BitmapFactory .decodeStream(inputStream) return bitmap } finally { if (inputStream != null) { inputStream.close() } entity.consumeContent() } } } catch (Exception e) { // Could provide a more explicit error message for IOException or // IllegalStateException getRequest.abort() Log.w('ImageDownloader', 'Error while retrieving bitmap from ' + url + e.toString()) } finally { if (client != null) { // client.close() } } return null } }

#10階

この問題が発生し、lruCacheを実装しました。 API 12以降が必要であるか、互換性v4ライブラリを使用していると思います。 lurCacheは高速メモリですが、予算もあるので、心配な場合はディスクを使用できます キャッシュしてください 見る ビットマップをキャッシュする すべてのコンテンツ。

今、私はどこからでも呼び出す私の実装を提供します シングルトンコード 、次のように:

//Where the first is a string and the other is a imageview to load. DownloadImageTask.getInstance().loadBitmap(avatarURL, iv_avatar)

これはキャッシュに理想的なコードであり、Web画像を取得するときにアダプタのgetViewで上記のコードを呼び出します。

public class DownloadImageTask { private LruCache mMemoryCache /* Create a singleton class to call this from multiple classes */ private static DownloadImageTask instance = null public static DownloadImageTask getInstance() { if (instance == null) { instance = new DownloadImageTask() } return instance } //Lock the constructor from public instances private DownloadImageTask() { // Get max available VM memory, exceeding this amount will throw an // OutOfMemory exception. Stored in kilobytes as LruCache takes an // int in its constructor. final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024) // Use 1/8th of the available memory for this memory cache. final int cacheSize = maxMemory / 8 mMemoryCache = new LruCache(cacheSize) { @Override protected int sizeOf(String key, Bitmap bitmap) { // The cache size will be measured in kilobytes rather than // number of items. return bitmap.getByteCount() / 1024 } } } public void loadBitmap(String avatarURL, ImageView imageView) { final String imageKey = String.valueOf(avatarURL) final Bitmap bitmap = getBitmapFromMemCache(imageKey) if (bitmap != null) { imageView.setImageBitmap(bitmap) } else { imageView.setImageResource(R.drawable.ic_launcher) new DownloadImageTaskViaWeb(imageView).execute(avatarURL) } } private void addBitmapToMemoryCache(String key, Bitmap bitmap) { if (getBitmapFromMemCache(key) == null) { mMemoryCache.put(key, bitmap) } } private Bitmap getBitmapFromMemCache(String key) { return mMemoryCache.get(key) } /* A background process that opens a http stream and decodes a web image. */ class DownloadImageTaskViaWeb extends AsyncTask { ImageView bmImage public DownloadImageTaskViaWeb(ImageView bmImage) { this.bmImage = bmImage } protected Bitmap doInBackground(String... urls) { String urldisplay = urls[0] Bitmap mIcon = null try { InputStream in = new java.net.URL(urldisplay).openStream() mIcon = BitmapFactory.decodeStream(in) } catch (Exception e) { Log.e('Error', e.getMessage()) e.printStackTrace() } addBitmapToMemoryCache(String.valueOf(urldisplay), mIcon) return mIcon } /* After decoding we update the view on the main UI. */ protected void onPostExecute(Bitmap result) { bmImage.setImageBitmap(result) } } }

#11階

チャームのように機能する方法、Androidクエリをお勧めします。

あなたはから始めることができます ここに これをダウンロード JAR ファイル

AQuery androidAQuery = new AQuery(this)

例えば:

androidAQuery.id(YOUR IMAGEVIEW).image(YOUR IMAGE TO LOAD, true, true, getDeviceWidth(), ANY DEFAULT IMAGE YOU WANT TO SHOW)

これは非常に高速で正確であり、アニメーションのロード、ビットマップの取得(必要な場合)など、他の多くの機能を見つけることができます。


#12階

これはAndroidでよくある問題であり、多くの人がさまざまな方法で解決しています。私の意見では、私が見た中で最高の解決策は ピカソ 比較的新しいライブラリ。主な内容は次のとおりです。

  • オープンソースですが、 ActionBarSherlock 有名Jake Whartonが率いる。
  • 1行のコードでネットワークまたはアプリケーションリソースから非同期で画像をロードする
  • 自動ListView検出
  • 自動ディスクおよびメモリキャッシュ
  • 変換をカスタマイズできます
  • 多くの構成可能なオプション
  • 超シンプルなAPI
  • 頻繁に更新する

#13階

Aqueryをお試しください 。画像を非同期でロードおよびキャッシュする驚くほど簡単な方法があります。


#14階

URLImageViewHelper これを行うのに役立つ素晴らしいライブラリです。


#15階

ピカソ

ジャックウォルトンのピカソライブラリを使用してください。 (ActionBarSherlockの開発者によって提供された完全なImageLoadingライブラリ)

Android用の強力な画像ダウンロードおよびキャッシュライブラリ。

画像は、Androidアプリケーションに待望のコンテキストと視覚効果を追加します。 Picassoを使用すると、アプリケーションに画像を簡単に読み込むことができます。通常は1行のコードのみです。

Picasso.with(context).load('http://i.imgur.com/DvpvklR.png').into(imageView)

ピカソは、Androidの多くの一般的な画像読み込みトラップを自動的に処理します。

アダプターでImageViewのリサイクルとダウンロードのキャンセルを処理します。最小限のメモリを使用した複雑な画像変換。自動メモリおよびディスクキャッシング。

ピカソジャックウォートンの図書館

滑り台

Glideは、Android向けの高速で効率的なオープンソースメディア管理フレームワークです。このフレームワークは、メディアのデコード、メモリとディスクのキャッシュ、およびリソースプールをシンプルで使いやすいインターフェイスにパックします。

Glideは、ビデオ静止画像、画像、アニメーションGIFの取得、デコード、表示をサポートしています。 Glideには、開発者がほぼすべてのネットワークスタックをプラグインできるようにする柔軟なAPIが含まれています。デフォルトでは、GlideはカスタムHttpUrlConnectionに基づくスタックを使用しますが、GoogleのVolleyプロジェクトまたはSquareのOkHttpライブラリにプラグインできるユーティリティライブラリも含まれています。

Glide.with(this).load('http://goo.gl/h8qOq7').into(imageView)

Glideの主な焦点は、あらゆる種類の画像リストを可能な限りスムーズかつ高速にスクロールさせることですが、Glideは、リモート画像の取得、サイズ変更、表示が必要なほとんどすべての状況でも効果的です。

グライド画像読み込みライブラリ

Facebookの壁画

Frescoは、Androidアプリケーションで画像を表示できる強力なシステムです。

壁画は画像の読み込みと表示を担当するため、これを行う必要はありません。ネットワーク、ローカルストレージ、またはローカルリソースから画像を読み込み、画像が到着するまでプレースホルダーを表示します。 1つはメモリに、もう1つは内部メモリに2つのレベルのキャッシュがあります。

壁画Github

Android 4.x以前のバージョンでは、Frescoは画像をAndroidメモリの特別な領域に配置します。これにより、アプリケーションの実行速度が向上し、ひどいOutOfMemoryErrorに悩まされる頻度が減ります。

壁画ドキュメント


#16階

1.1。 ピカソ アプリケーションに画像を簡単にロードできます。通常は1行のコードのみです。

Gradleを使用する:

implementation 'com.squareup.picasso:picasso:2.71828'

たった1行のコード!

Picasso.get().load('http://i.imgur.com/DvpvklR.png').into(imageView)

二。 滑り台 Androidの画像読み込みおよびキャッシュライブラリは、スムーズなスクロールに重点を置いています

Gradleを使用する:

repositories { mavenCentral() google() } dependencies { implementation 'com.github.bumptech.glide:glide:4.7.1' annotationProcessor 'com.github.bumptech.glide:compiler:4.7.1' }

//簡単なビューの場合:

Glide.with(this).load('http://i.imgur.com/DvpvklR.png').into(imageView)

3.3。 新鮮な これは、Androidアプリケーションで画像を表示できる強力なシステムです。 Frescoは画像の読み込みと表示を担当するため、これを行う必要はありません。

壁画入門


#17階

画像の遅延読み込みに使用するライブラリがわからない場合は、これが簡単なヒントです。

4つの基本的な方法があります。

  1. DIY =>最善の解決策ではありませんが、他のライブラリを使用する手間をかけたくない場合は、一部の画像で

  2. ボレーの遅延読み込みライブラリ=> Androidの男。とても良いです、すべてが大丈夫です、しかしドキュメントは貧弱なので、使うのは面倒です。

  3. ピカソ:これはシンプルで効果的なソリューションです。導入する正確な画像サイズを指定することもできます。使い方は非常に簡単ですが、多数の画像を処理する必要があるアプリケーションにとっては、それほど「優れた」ものではない場合があります。

  4. UIL:画像の読み込みを遅らせるための最良の方法。 (もちろんあなたの許可を得て)イメージをキャッシュし、ローダーを一度初期化してから、作業を終了することができます。これまでのところ、私が見た中で最も成熟した非同期画像読み込みライブラリです。


#18階

更新:この回答は現在無効であることに注意してください。 ガベージコレクターはSoftReferenceとWeakReferenceに対して積極的な対策を講じているため、このコードは新しいアプリケーションには適していません。 (代わりに、他の回答で提案されているライブラリを試してください。 ユニバーサルイメージローダー 。)

コードを提供してくれたJamesと、SoftReferenceの使用を提案してくれたBao-Longに感謝します。 JamesのコードにSoftReferenceの変更を実装しました。残念ながら、SoftReferencesにより、画像のガベージコレクションが速すぎました。私の場合、リストのサイズが制限されており、画像が小さいため、SoftReferenceがないと便利です。

1年前、GoogleグループでSoftReferencesについての議論がありました。 スレッドへのリンク 。時期尚早のガベージコレクションの解決策として、dalvik.system.VMRuntime.setMinimumHeapSize()を使用してVMヒープサイズを手動で設定する可能性を推奨していますが、これは私にはあまり魅力的ではありません。

public DrawableManager() { drawableMap = new HashMap() } public Drawable fetchDrawable(String urlString) { SoftReference drawableRef = drawableMap.get(urlString) if (drawableRef != null) { Drawable drawable = drawableRef.get() if (drawable != null) return drawable // Reference has expired so remove the key from drawableMap drawableMap.remove(urlString) } if (Constants.LOGGING) Log.d(this.getClass().getSimpleName(), 'image url:' + urlString) try { InputStream is = fetch(urlString) Drawable drawable = Drawable.createFromStream(is, 'src') drawableRef = new SoftReference(drawable) drawableMap.put(urlString, drawableRef) if (Constants.LOGGING) Log.d(this.getClass().getSimpleName(), 'got a thumbnail drawable: ' + drawable.getBounds() + ', ' + drawable.getIntrinsicHeight() + ',' + drawable.getIntrinsicWidth() + ', ' + drawable.getMinimumHeight() + ',' + drawable.getMinimumWidth()) return drawableRef.get() } catch (MalformedURLException e) { if (Constants.LOGGING) Log.e(this.getClass().getSimpleName(), 'fetchDrawable failed', e) return null } catch (IOException e) { if (Constants.LOGGING) Log.e(this.getClass().getSimpleName(), 'fetchDrawable failed', e) return null } } public void fetchDrawableOnThread(final String urlString, final ImageView imageView) { SoftReference drawableRef = drawableMap.get(urlString) if (drawableRef != null) { Drawable drawable = drawableRef.get() if (drawable != null) { imageView.setImageDrawable(drawableRef.get()) return } // Reference has expired so remove the key from drawableMap drawableMap.remove(urlString) } final Handler handler = new Handler() { @Override public void handleMessage(Message message) { imageView.setImageDrawable((Drawable) message.obj) } } Thread thread = new Thread() { @Override public void run() { //TODO : set imageView to a 'pending' image Drawable drawable = fetchDrawable(urlString) Message message = handler.obtainMessage(1, drawable) handler.sendMessage(message) } } thread.start() }

#19階

最高のユニバーサルローダーを試す必要があります。遅延読み込みで多くのRnDを実行した後、私はそれを使用しています。

ユニバーサルイメージローダー

特徴

  • マルチスレッド画像の読み込み(非同期または同期)
  • ImageLoader構成の広範なカスタマイズ(スレッドエグゼキューター、ダウンローダー、デコーダー、メモリとディスクキャッシュ、画像オプションの表示など)
  • 表示画像の呼び出しごとに多くのカスタマイズオプションがあります(スタブ画像、キャッシュスイッチ、デコードオプション、ビットマップ処理と表示など)。
  • メモリやディスク(デバイスファイルシステムまたはSDカード)での画像のキャッシュ
  • ロードプロセスを監視します(ダウンロードの進行状況を含む)

Android2.0以降のサポート

画像


#20階

私がやります 持った 画像付き 怠惰なリストの簡単なデモンストレーション (GitHubにあります)。

基本的な使い方

ImageLoader imageLoader=new ImageLoader(context) ... imageLoader.DisplayImage(url, imageView)

AndroidManifest.xmlに次の権限を追加することを忘れないでください。

Please

ImageLoaderインスタンスを1つだけ作成し、アプリケーションで再利用します。このようにして、画像のキャッシュがより効率的になります。

これは誰かを助けるかもしれません。バックグラウンドスレッドで画像をダウンロードします。画像はSDカードと内部メモリにキャッシュされます。キャッシュの実装は非常に単純で、デモンストレーションには十分です。 inSampleSizeを使用して画像をデコードし、メモリ消費を削減します。また、リサイクルされたビューを正しく処理するようにしています。

画像


#21階

上記のコードにはすべて独自の価値がありますが、私の個人的な経験では、Picassoを使用してみてください。

ピカソ この目的専用のライブラリであり、実際には、キャッシュと他のすべてのネットワーク操作を自動的に管理します。ライブラリをプロジェクトに追加する必要があります。1行のコードを記述することで、リモートURLから画像を読み込むことができます。

こちらをご覧ください: http//code.tutsplus.com/tutorials/android-sdk-working-with-picasso--cms-22149


#22階

GillesDebunneによるチュートリアルマルチ パフォーマンスのためのパフォーマンス

これはAndroidデベロッパーブログからのものです。推奨されるコードの使用法:

  • AsyncTasks
  • 限定サイズハードFIFO cache
  • ソフトで簡単garbage collectキャッシュ。
  • ダウンロード時Drawable of プレースホルダー

画像


#23階

スライドライブラリを使用します。それは私のために働きます、それはあなたのコードのために働きます、それは画像とgifのために働きます。

ImageView imageView = (ImageView) findViewById(R.id.test_image) GlideDrawableImageViewTarget imagePreview = new GlideDrawableImageViewTarget(imageView) Glide .with(this) .load(url) .listener(new RequestListener() { @Override public boolean onException(Exception e, String model, Target target, boolean isFirstResource) { return false } @Override public boolean onResourceReady(GlideDrawable resource, String model, Target target, boolean isFromMemoryCache, boolean isFirstResource) { return false } }) .into(imagePreview) }

#24階

Facebookのシマーレイアウトを表示したい場合は、公式のFacebookライブラリがあります。 FaceBookシマーAndroid

それはすべてを処理します、あなたは入れ子の方法できらめきフレームに必要なデザインコードを置く必要があるだけです。これはサンプルコードです。

ShimmerFrameLayout shimmerContainer = (ShimmerFrameLayout) findViewById(R.id.shimmer_view_container) shimmerContainer.startShimmerAnimation()

これはそのJavaコードです。

implementation 'com.facebook.shimmer:shimmer:root@xxxxx'

この依存関係をgradleファイルに追加します。

package com.wilson.android.library /* Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the 'License') you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ import java.io.IOException public class DrawableManager { private final Map drawableMap public DrawableManager() { drawableMap = new HashMap() } public Drawable fetchDrawable(String urlString) { if (drawableMap.containsKey(urlString)) { return drawableMap.get(urlString) } Log.d(this.getClass().getSimpleName(), 'image url:' + urlString) try { InputStream is = fetch(urlString) Drawable drawable = Drawable.createFromStream(is, 'src') if (drawable != null) { drawableMap.put(urlString, drawable) Log.d(this.getClass().getSimpleName(), 'got a thumbnail drawable: ' + drawable.getBounds() + ', ' + drawable.getIntrinsicHeight() + ',' + drawable.getIntrinsicWidth() + ', ' + drawable.getMinimumHeight() + ',' + drawable.getMinimumWidth()) } else { Log.w(this.getClass().getSimpleName(), 'could not get thumbnail') } return drawable } catch (MalformedURLException e) { Log.e(this.getClass().getSimpleName(), 'fetchDrawable failed', e) return null } catch (IOException e) { Log.e(this.getClass().getSimpleName(), 'fetchDrawable failed', e) return null } } public void fetchDrawableOnThread(final String urlString, final ImageView imageView) { if (drawableMap.containsKey(urlString)) { imageView.setImageDrawable(drawableMap.get(urlString)) } final Handler handler = new Handler() { @Override public void handleMessage(Message message) { imageView.setImageDrawable((Drawable) message.obj) } } Thread thread = new Thread() { @Override public void run() { //TODO : set imageView to a 'pending' image Drawable drawable = fetchDrawable(urlString) Message message = handler.obtainMessage(1, drawable) handler.sendMessage(message) } } thread.start() } private InputStream fetch(String urlString) throws MalformedURLException, IOException { DefaultHttpClient httpClient = new DefaultHttpClient() HttpGet request = new HttpGet(urlString) HttpResponse response = httpClient.execute(request) return response.getEntity().getContent() } }

これはそれがどのように見えるかです。


#25階

これを行う方法は、スレッドを開始してバックグラウンドで画像をダウンロードし、各リストアイテムのコールバックを提供することです。画像のダウンロードが完了すると、コールバックが呼び出され、リストアイテムのビューが更新されます。

ただし、この方法は、ビューをリサイクルする場合はうまく機能しません。


#26階

これは、アプリケーションによって現在表示されている画像を保存するために作成したコンテンツです。ここで使用されている「Log」オブジェクトは、Android内の最終的なLogクラスのカスタムラッパーであることに注意してください。

import java.util.Map import java.util.HashMap import java.util.LinkedList import java.util.Collections import java.util.WeakHashMap import java.lang.ref.SoftReference import java.util.concurrent.Executors import java.util.concurrent.ExecutorService import android.graphics.drawable.Drawable import android.widget.ImageView import android.os.Handler import android.os.Message import java.io.InputStream import java.net.MalformedURLException import java.io.IOException import java.net.URL import java.net.URLConnection public class DrawableBackgroundDownloader { private final Map mCache = new HashMap() private final LinkedList mChacheController = new LinkedList () private ExecutorService mThreadPool private final Map mImageViews = Collections.synchronizedMap(new WeakHashMap()) public static int MAX_CACHE_SIZE = 80 public int THREAD_POOL_SIZE = 3 /** * Constructor */ public DrawableBackgroundDownloader() { mThreadPool = Executors.newFixedThreadPool(THREAD_POOL_SIZE) } /** * Clears all instance data and stops running threads */ public void Reset() { ExecutorService oldThreadPool = mThreadPool mThreadPool = Executors.newFixedThreadPool(THREAD_POOL_SIZE) oldThreadPool.shutdownNow() mChacheController.clear() mCache.clear() mImageViews.clear() } public void loadDrawable(final String url, final ImageView imageView,Drawable placeholder) { mImageViews.put(imageView, url) Drawable drawable = getDrawableFromCache(url) // check in UI thread, so no concurrency issues if (drawable != null) { //Log.d(null, 'Item loaded from mCache: ' + url) imageView.setImageDrawable(drawable) } else { imageView.setImageDrawable(placeholder) queueJob(url, imageView, placeholder) } } private Drawable getDrawableFromCache(String url) { if (mCache.containsKey(url)) { return mCache.get(url).get() } return null } private synchronized void putDrawableInCache(String url,Drawable drawable) { int chacheControllerSize = mChacheController.size() if (chacheControllerSize > MAX_CACHE_SIZE) mChacheController.subList(0, MAX_CACHE_SIZE/2).clear() mChacheController.addLast(drawable) mCache.put(url, new SoftReference(drawable)) } private void queueJob(final String url, final ImageView imageView,final Drawable placeholder) { /* Create handler in UI thread. */ final Handler handler = new Handler() { @Override public void handleMessage(Message msg) { String tag = mImageViews.get(imageView) if (tag != null && tag.equals(url)) { if (imageView.isShown()) if (msg.obj != null) { imageView.setImageDrawable((Drawable) msg.obj) } else { imageView.setImageDrawable(placeholder) //Log.d(null, 'fail ' + url) } } } } mThreadPool.submit(new Runnable() { @Override public void run() { final Drawable bmp = downloadDrawable(url) // if the view is not visible anymore, the image will be ready for next time in cache if (imageView.isShown()) { Message message = Message.obtain() message.obj = bmp //Log.d(null, 'Item downloaded: ' + url) handler.sendMessage(message) } } }) } private Drawable downloadDrawable(String url) { try { InputStream is = getInputStream(url) Drawable drawable = Drawable.createFromStream(is, url) putDrawableInCache(url,drawable) return drawable } catch (MalformedURLException e) { e.printStackTrace() } catch (IOException e) { e.printStackTrace() } return null } private InputStream getInputStream(String urlString) throws MalformedURLException, IOException { URL url = new URL(urlString) URLConnection connection connection = url.openConnection() connection.setUseCaches(true) connection.connect() InputStream response = connection.getInputStream() return response } }

#27階

リストビューで画像を遅延ロードする方法を説明するチュートリアルを作成しました。リサイクルと並行性の問題について詳しく説明します。また、固定スレッドプールを使用して、多数のスレッドを防止しています。

Listviewチュートリアルでの画像の遅延読み込み


#28階

高性能ローダー-ここで提案された方法を確認した後、私は使用しました ベンの解決策 そして、いくつかの変更を加えました-

  1. ドローアブルを使用する方がビットマップを使用するよりも高速であることに気付いたので、ドローアブルに切り替えました

  2. SoftReferenceを使用するのは素晴らしいことですが、キャッシュされた画像が頻繁に削除される原因になるため、事前定義されたサイズに達するまで画像が削除されないように画像参照を保存するリンクリストを追加しました。

  3. InputStreamを開くために、java.net.URLConnectionを使用しました。これにより、Webキャッシングを使用できます(最初に応答キャッシングを設定する必要がありますが、それは別の問題です)

私のコード:

|_+_|

#29階

より良い例を追加したいだけです XMLアダプター 。 Googleがそれを使用しているので、OutOfMemoryエラーを回避するために同じロジックも使用しています。

基本的に、 このImageDownloader あなたの答えです(それはあなたの要件のほとんどをカバーしているからです)。特定の機能を実装することもできます。


#30階

オープンソースツールの使用をお勧めします ユニバーサルイメージローダー 。もともとはヒョードル・ヴラソフに基づいたプロジェクトでした LazyList 、そしてそれ以来大幅に改善されています。

  • マルチスレッド画像の読み込み
  • ImageLoaderの構成は、広範囲に調整できます(スレッド実行プログラム、ダウンローダー、デコーダー、メモリとディスクのキャッシュ、画像の表示オプションなど)。
  • メモリおよび/またはデバイスファイルシステム(またはSDカード)での画像キャッシュの可能性
  • ロードプロセスを「監視」する可能性
  • 個々のオプションを使用して、各表示画像の呼び出しをカスタマイズできます
  • ウィジェットのサポート
  • Android2.0以降のサポート