私はいくつかの画像とそれらの画像に関連するキャプションを表示するためにListView
を使っています。インターネットから画像を取得しています。テキストが表示されている間にUIがロックされず、ダウンロードされたとおりに画像が表示されるように、画像を遅延ロードする方法はありますか。
画像の総数は決まっていません。
これは、私のアプリが現在表示している画像を保持するために作成したものです。ここで使用されている "Log"オブジェクトは、Android内部の最終的なLogクラスの周りの私のカスタムラッパーです。
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<String, Drawable> drawableMap;
public DrawableManager() {
drawableMap = new HashMap<String, Drawable>();
}
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();
}
}
私は 遅延リストの簡単なデモを作成しました (GitHubにあります)画像付き。
基本的な使い方
ImageLoader imageLoader=new ImageLoader(context); ... imageLoader.DisplayImage(url, imageView);
AndroidManifest.xmlに次の権限を追加することを忘れないでください。
<uses-permission Android:name="Android.permission.INTERNET"/> <uses-permission Android:name="Android.permission.WRITE_EXTERNAL_STORAGE"/> Please
imageLoaderのインスタンスを1つだけ作成し、それをアプリケーション全体で再利用します。このようにして、画像キャッシュははるかに効率的になります。
誰かに役立つかもしれません。バックグラウンドスレッドで画像をダウンロードします。画像はSDカードとメモリにキャッシュされています。キャッシュの実装は非常に単純で、デモには十分です。メモリ消費量を減らすためにinSampleSizeで画像をデコードします。私はまたリサイクルされた意見を正しく扱うようにします。
オープンソースのインストゥルメントUniversal Image Loaderをお勧めします。もともとFedor Vlasovのプロジェクト LazyList に基づいており、それ以来大幅に改良されてきました。
パフォーマンスのためのマルチスレッド 、Gilles Debunneによるチュートリアル。
これはAndroid Developers Blogからのものです。提案されたコードは以下を使用します。
AsyncTasks
。FIFO cache
。garbage collect
されたキャッシュ。Drawable
となります。更新:この答えは今ではほとんど効果がないことに注意してください。ガベージコレクタはSoftReferenceとWeakReferenceに積極的に作用するため、このコードは新しいアプリケーションには適していません。 (代わりに、 Universal Image Loader のようなライブラリを試してみてください。)
コードを提供してくれたJames、そしてSoftReferenceを使うことを提案してくれたBao-Longに感謝します。私はJamesのコードにSoftReferenceの変更を加えました。残念なことにSoftReferencesは私の画像があまりにも早くガベージコレクションされる原因となりました。私の場合、私のリストのサイズは限られていて私の画像は小さいので、SoftReferenceのものがなくても大丈夫でした。
グーグルグループのSoftReferencesに関して1年前からの議論があります: スレッドへのリンク 。早すぎるガベージコレクションの解決策として、彼らはdalvik.system.VMRuntime.setMinimumHeapSize()を使用してVMヒープサイズを手動で設定する可能性を示唆していますが、これはあまり魅力的ではありません。
public DrawableManager() {
drawableMap = new HashMap<String, SoftReference<Drawable>>();
}
public Drawable fetchDrawable(String urlString) {
SoftReference<Drawable> 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>(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<Drawable> 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();
}
ピカソ
Jake WhartonのPicasso Libraryを使用してください。 (ActionBarSherlockの開発者であるPerfect ImageLoading Library)
Android用の強力な画像ダウンロードおよびキャッシュライブラリ。
画像は、Androidアプリケーションに必要なコンテキストと視覚的な効果を追加します。 Picassoはあなたのアプリケーションで手間のかからない画像の読み込みを可能にします - しばしば一行のコードで!
Picasso.with(context).load("http://i.imgur.com/DvpvklR.png").into(imageView);
Androidに画像をロードする際のよくある落とし穴は、Picassoによって自動的に処理されます。
ImageViewのリサイクルとダウンロードのキャンセルをアダプタで処理する。最小限のメモリ使用で複雑な画像変換自動メモリおよびディスクキャッシュ.
グライド
GlideはAndroid用の高速で効率的なオープンソースメディア管理フレームワークで、メディアのデコード、メモリとディスクのキャッシュ、そしてリソースプーリングをシンプルで使いやすいインターフェースにまとめています。
グライドは、静止画、画像、およびアニメーションGIFの取得、デコード、および表示をサポートします。 Glideには、開発者がほとんどすべてのネットワークスタックにプラグインできる柔軟なAPIが含まれています。デフォルトでは、GlideはカスタムHttpUrlConnectionベースのスタックを使用しますが、代わりにGoogleのVolleyプロジェクトまたはSquareのOkHttpライブラリにプラグインするユーティリティライブラリも含みます。
Glide.with(this).load("http://goo.gl/h8qOq7").into(imageView);
Glideの主な目的は、あらゆる種類の画像リストをできる限りスムーズかつ高速にスクロールすることです。ただし、Glideは、リモート画像の取得、サイズ変更、表示が必要なほとんどの場合にも効果的です。
FacebookのFresco
フレスコ画は、Androidアプリケーションで画像を表示するための強力なシステムです。
Frescoは画像の読み込みと表示の面倒を見るので、そうする必要はありません。ネットワーク、ローカルストレージ、またはローカルリソースから画像をロードし、その画像が届くまでプレースホルダを表示します。 2つのレベルのキャッシュがあります。 1つはメモリ内に、もう1つは内部ストレージにあります。
Android 4.x以前では、FrescoはAndroidメモリの特別な領域に画像を配置します。これはあなたのアプリケーションがより速く動くことを可能にします - そして恐ろしいOutOfMemoryErrorを受ける頻度ははるかに少なくなります。
ハイパフォーマンスローダー - ここで提案された方法を検討した後、私は Benの解決策 をいくつか変更して使用しました -
ドロアブルを使った作業はビットマップを使った作業より速いので、代わりにドロアブルを使用します。
SoftReferenceを使用するのは素晴らしいことですが、キャッシュされたイメージが頻繁に削除されるため、イメージ参照を保持するリンクリストを追加し、イメージが事前定義サイズに達するまで削除されないようにします
InputStreamを開くには、Webキャッシュを使用できるようにするJava.net.URLConnectionを使用しました(最初に応答キャッシュを設定する必要がありますが、これは別の話です)。
私のコード:
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<String, SoftReference<Drawable>> mCache = new HashMap<String, SoftReference<Drawable>>();
private final LinkedList <Drawable> mChacheController = new LinkedList <Drawable> ();
private ExecutorService mThreadPool;
private final Map<ImageView, String> mImageViews = Collections.synchronizedMap(new WeakHashMap<ImageView, String>());
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>(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;
}
}
私はこのAndroidトレーニングをフォローしましたが、メインUIをブロックすることなく画像をダウンロードするのに優れた仕事をしていると思います。それはまたキャッシングを処理し、そして多くの画像をスクロールすることを扱う: 大きなビットマップを効率的にロードする
1. Picasso を使用すると、アプリケーションに手間のかからない画像を読み込むことができます。多くの場合、1行のコードで行えます。
Gradleを使用:
implementation 'com.squareup.picasso:picasso:2.71828'
たった1行のコードです。
Picasso.get().load("http://i.imgur.com/DvpvklR.png").into(imageView);
2. グライド スムーズスクロールに焦点を当てた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. fresco は、Androidアプリケーションで画像を表示するための強力なシステムです。Frescoは、画像の読み込みと表示を行います。
私はリストビューで画像を遅延ロードする方法を説明するチュートリアルを書きました。私はリサイクルと並行性の問題についていくつかの詳細に入ります。私はまた、固定スレッドプールを使用して、多数のスレッドが生成されるのを防ぎます。
私がやりたいのは、バックグラウンドで画像をダウンロードし、それに各リストアイテムのコールバックを渡すためのスレッドを起動することです。画像のダウンロードが終了すると、リストアイテムのビューを更新するコールバックを呼び出します。
ただし、ビューをリサイクルしている場合、この方法はあまりうまくいきません。
もう1つ良い例として、XML Adaptersを追加します。 Googleによって使用されているので、OutOfMemoryエラーを回避するために同じロジックを使用しています。
基本的に this ImageDownloader があなたの答えです(それはあなたの要求の大部分をカバーするので)。その中に実装できるものもあります。
私は新しいAndroid Volley Library com.Android.volley.toolbox.NetworkImageView
のNetworkImageViewを使ってきましたが、それはかなりうまくいっているようです。どうやら、これは Google Play や他の新しいGoogleアプリケーションで使われているのと同じ見方です。確かにチェックする価値があります。
これはAndroid上でよく見られる問題で、多くの人によってさまざまな方法で解決されています。私の意見では、私が見た最も良い解決策は Picasso と呼ばれる比較的新しいライブラリです。これがハイライトです。
Jake Wharton
が先頭に立った。ListView
検出さて、インターネットからの画像読み込み時間には多くの解決策があります。ライブラリ Android-Query を使用することもできます。それはあなたにすべての必要な活動を与えるでしょう。あなたが何をしたいのかを確かめて、ライブラリーの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;
}
それはあなたの遅延読み込みの問題を解決するはずです。
私はこの問題がAndroid開発者の間で非常に人気があると思います、そしてこの問題を解決すると主張するそのようなライブラリがたくさんありますが、そのうちほんの一部だけが注目されているようです。 AQuery はそのようなライブラリの1つですが、あらゆる面でそれらのほとんどより優れているので、試す価値があります。
あなたはこのユニバーサルローダーを試す必要があります。私は遅延ロードで多くのRnDを行った後にこれを使用しています。
機能
Android 2.0以降のサポート
Shutterbug 、Applidiumの軽量なSDWebImage(iOS上のNiceライブラリ)のAndroidへの移植版をご覧ください。これは非同期キャッシュをサポートし、失敗したURLを保存し、並行性をうまく処理し、そして有用なサブクラスが含まれています。
プルリクエスト(およびバグレポート)も大歓迎です。
DroidParts has ImageFetcher それは始めるためにゼロ設定を必要とする。
例:クローン DroidPartsGram
Lazy-loading imagesにどのライブラリを使うべきかについて決定が下されていない人のためのちょっとしたコツ。
基本的な方法は4つあります。
DIY =>最善の解決策ではありませんが、いくつかの画像を使用し、他のライブラリを使用する手間をかけずに行きたい場合は
Volley's Lazy Loading library => Androidのみんなから。それはいいことだがすべてが十分に文書化されていないので、使用するのに問題がある。
ピカソ:うまくいく簡単な解決策として、持ち込む画像の正確なサイズを指定することもできます。使用するのは非常に簡単ですが、膨大な量の画像を処理する必要があるアプリケーションには「高性能」とは言えません。
UIL:画像を遅延ロードするための最良の方法。画像をキャッシュして(もちろん許可が必要です)、ローダーを一度初期化してから作業を終えることができます。私が今まで見た中で最も成熟した非同期イメージローディングライブラリ。
Novodaにはすばらしい lazy image loading library があり、Songkick、Podio、SecretDJ、ImageSearchなどの多くのアプリはそれらのライブラリを使用します。
彼らのライブラリはGithubでホストされている here であり、かなり活発な issueトラッカー を持っています。この回答を書いている時点で300以上のコミットがあり、彼らのプロジェクトもかなり活発になっているようです。
上記のコードはすべて独自の価値がありますが、私の個人的な経験から、Picassoを試してみてください。
Picasso はこの目的のためのライブラリで、実際にはキャッシュやその他すべてのネットワーク操作を自動的に管理します。プロジェクトにライブラリを追加し、そこからイメージをロードするコードを1行書くだけですリモートURL.
こちらをご覧ください: http://code.tutsplus.com/tutorials/Android-sdk-working-with-picasso--cms-22149
グライドライブラリを使用してください。それは私のために働いたし、あなたのコードのためにも働くでしょう。それはGIFと同様に両方の画像にも働きます。
ImageView imageView = (ImageView) findViewById(R.id.test_image);
GlideDrawableImageViewTarget imagePreview = new GlideDrawableImageViewTarget(imageView);
Glide
.with(this)
.load(url)
.listener(new RequestListener<String, GlideDrawable>() {
@Override
public boolean onException(Exception e, String model, Target<GlideDrawable> target, boolean isFirstResource) {
return false;
}
@Override
public boolean onResourceReady(GlideDrawable resource, String model, Target<GlideDrawable> target, boolean isFromMemoryCache, boolean isFirstResource) {
return false;
}
})
.into(imagePreview);
}
FacebookのようなShimmerのレイアウトを表示したい場合は、そのための公式のFacebookライブラリがあります。 フェイスブックシマーアンドロイド
それはすべての面倒を見る、あなたはちょうどあなたの望みのデザインコードをきらめくフレームの中に入れ子にして置く必要があります。これがサンプルコードです。
<com.facebook.shimmer.ShimmerFrameLayout
Android:id=“@+id/shimmer_view_container”
Android:layout_width=“wrap_content”
Android:layout_height="wrap_content"
shimmer:duration="1000">
<here will be your content to display />
</com.facebook.shimmer.ShimmerFrameLayout>
そして、これがそのためのJavaコードです。
ShimmerFrameLayout shimmerContainer = (ShimmerFrameLayout) findViewById(R.id.shimmer_view_container);
shimmerContainer.startShimmerAnimation();
あなたのgradleファイルにこの依存関係を追加してください。
implementation 'com.facebook.shimmer:shimmer:0.1.0@aar'
アクエリ をしてみてください。画像を非同期的にロードおよびキャッシュするための驚くほど簡単な方法があります。
私は魅力のように動作する別の方法をお勧めすることができます。AndroidQuery。
_ jar _ ファイルは here からダウンロードできます。
AQuery androidAQuery = new AQuery(this);
例として:
androidAQuery.id(YOUR IMAGEVIEW).image(YOUR IMAGE TO LOAD, true, true, getDeviceWidth(), ANY DEFAULT IMAGE YOU WANT TO SHOW);
それは非常に速くて正確です、そしてこれを使用することはあなたがロードする時にアニメーションのような多くのより多くの機能を見つけることができる、(必要ならば)ビットマップを得る、など。
URLImageViewHelper はあなたがそれをするのを助ける驚くべきライブラリです。
public class ImageDownloader {
Map<String, Bitmap> imageCache;
public ImageDownloader() {
imageCache = new HashMap<String, Bitmap>();
}
// 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<String, Void, Bitmap> {
private String url;
private final WeakReference<ImageView> imageViewReference;
public BitmapDownloaderTask(ImageView imageView) {
imageViewReference = new WeakReference<ImageView>(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<BitmapDownloaderTask> bitmapDownloaderTaskReference;
public DownloadedDrawable(BitmapDownloaderTask bitmapDownloaderTask) {
super(Color.WHITE);
bitmapDownloaderTaskReference = new WeakReference<BitmapDownloaderTask>(
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;
}
}
私はこの問題を抱えていて、lruCacheを実装しました。私はあなたがAPI 12以降を必要とするか、または互換性v4ライブラリを使用すると思います。 lurCacheは高速メモリですが、予算もありますので、ディスクキャッシュを使うことができるのであれば...Caching Bitmapsで説明されています。
私は今、私がこのような場所から呼び出す singleton である私の実装を提供します。
//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<String, Bitmap> 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<String, Bitmap>(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<String, Void, Bitmap> {
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);
}
}
}
あなたはAquery Android ライブラリを怠惰なロードイメージとリストビューのために試すことができます...以下のコードはあなたを助けるかもしれません..... ここからライブラリをダウンロードします 。
AQuery aq = new AQuery(mContext);
aq.id(R.id.image1).image("http://data.whicdn.com/images/63995806/original.jpg");
もう1つの方法は、getView()メソッドのスレッドでアダプタを使用することです。
Thread pics_thread = new Thread(new Runnable() {
@Override
public void run() {
Bitmap bitmap = getPicture(url);
if(bitmap != null) {
runOnUiThread(new Runnable() {
@Override
public void run() {
holder.imageview.setImageBitmap(bitmap);
adapter.notifyDataSetChanged();
}
});
}
}
});
pics_thread.start();
もちろん、余分な操作を避けるためにイメージを常にキャッシュする必要があります。イメージをHashMap配列に入れたり、イメージが配列内に存在するかどうかを確認したり、存在しない場合はスレッドを続行したりします。また、常にメモリをリークしていないことを確認してください。ビットマップやドロアブルは、多くの場合メモリを消費します。コードを最適化するのはあなた次第です。
droidQuery を使います。 URLから画像を読み込む方法は2つあります。最初の(速記)は簡単です:
$.with(myView).image(url);
これはArrayAdapter
のgetView(...)
メソッドに非常に簡単に追加できます。
この手っ取り早い方法ではもっと制御しやすくなり、ここでは説明しないオプション(キャッシュやコールバックなど)もありますが、出力サイズを200px x 200pxに指定する基本的な実装はここにあります。
$.ajax(new AjaxOptions().url(url)
.type("GET")
.dataType("image")
.imageWidth(200).imageHeight(200)
.success(new Function() {
@Override
public void invoke($ droidQuery, Object... params) {
myImageView.setImageBitmap((Bitmap) params[0]);
}
})
.error(new Function() {
@Override
public void invoke($ droidQuery, Object... params) {
AjaxError e = (AjaxError) params[0];
Log.e("$", "Error " + e.status + ": " + e.error);
}
})
);
Universal Image Loaderやandroidimageloaderなどのさまざまな画像ライブラリの使用について既にいくつかの回答があります。これは古い質問ですが、まだこのようなものを探している人には、画像の読み込み/キャッシュ用に いくつかのそのようなライブラリ があります。
listview.Itに画像をダウンロードしてロードするには、以下のクラスを使用してください。ダウンロードすると、すべての画像がキャッシュされます。画像を遅延ロードすることもできます。
package com.fudiyoxpress.images;
import Java.io.File;
import Java.io.FileInputStream;
import Java.io.FileNotFoundException;
import Java.io.FileOutputStream;
import Java.io.IOException;
import Java.io.InputStream;
import Java.io.OutputStream;
import Java.net.HttpURLConnection;
import Java.net.URL;
import Java.util.Collections;
import Java.util.Map;
import Java.util.WeakHashMap;
import Java.util.concurrent.ExecutorService;
import Java.util.concurrent.Executors;
import Android.content.Context;
import Android.graphics.Bitmap;
import Android.graphics.BitmapFactory;
import Android.os.Handler;
import Android.widget.ImageView;
import com.fudiyoxpress.R;
import com.fudiyoxpress.config.Config;
import com.fudiyoxpress.Twitter.ScaleBitmap;
public class ImageLoader {
// Initialize MemoryCache
MemoryCache memoryCache = new MemoryCache();
FileCache fileCache;
Context C;
// Create Map (collection) to store image and image url in key value pair
private Map<ImageView, String> imageViews = Collections
.synchronizedMap(new WeakHashMap<ImageView, String>());
ExecutorService executorService;
// handler to display images in UI thread
Handler handler = new Handler();
public ImageLoader(Context context) {
C = context;
fileCache = new FileCache(context);
// Creates a thread pool that reuses a fixed number of
// threads operating off a shared unbounded queue.
executorService = Executors.newFixedThreadPool(5);
}
// default image show in list (Before online image download)
final int stub_id = R.drawable.restlogoplaceholder;
public void DisplayImage(String url, ImageView imageView, Context context,
boolean header_flag) {
Bitmap largeIcon = BitmapFactory.decodeResource(context.getResources(),
R.drawable.restlogoplaceholder);
header_flag = false;
// Store image and url in Map
imageViews.put(imageView, url);
// Check image is stored in MemoryCache Map or not (see
// MemoryCache.Java)
Bitmap bitmap = memoryCache.get(url);
if (bitmap != null) {
// if image is stored in MemoryCache Map then
// Show image in listview row
Bitmap b = ScaleBitmap
.getScaledBitmap(context, bitmap, header_flag);
imageView.setImageBitmap(b);
} else {
// queue Photo to download from url
queuePhoto(url, imageView, header_flag);
// Before downloading image show default image
imageView.setImageBitmap(ScaleBitmap.getScaledBitmap(context,
largeIcon, header_flag));
}
}
private void queuePhoto(String url, ImageView imageView, boolean header_flag) {
// Store image and url in PhotoToLoad object
PhotoToLoad p = new PhotoToLoad(url, imageView, header_flag);
// pass PhotoToLoad object to PhotosLoader runnable class
// and submit PhotosLoader runnable to executers to run runnable
// Submits a PhotosLoader runnable task for execution
executorService.submit(new PhotosLoader(p));
}
// Task for the queue
private class PhotoToLoad {
public String url;
public ImageView imageView;
public boolean b;
public PhotoToLoad(String u, ImageView i, boolean header_flag) {
url = u;
imageView = i;
b = header_flag;
}
}
class PhotosLoader implements Runnable {
PhotoToLoad photoToLoad;
PhotosLoader(PhotoToLoad photoToLoad) {
this.photoToLoad = photoToLoad;
}
@Override
public void run() {
try {
// Check if image already downloaded
if (imageViewReused(photoToLoad))
return;
// download image from web url
Bitmap bmp = getBitmap(photoToLoad.url);
// set image data in Memory Cache
memoryCache.put(photoToLoad.url, bmp);
if (imageViewReused(photoToLoad))
return;
// Get bitmap to display
BitmapDisplayer bd = new BitmapDisplayer(bmp, photoToLoad);
// Causes the Runnable bd (BitmapDisplayer) to be added to the
// message queue.
// The runnable will be run on the thread to which this handler
// is attached.
// BitmapDisplayer run method will call
handler.post(bd);
} catch (Throwable th) {
// th.printStackTrace();
}
}
}
private Bitmap getBitmap(String url) {
File f = fileCache.getFile(url);
// from SD cache
// CHECK : if trying to decode file which not exist in cache return null
Bitmap b = decodeFile(f);
if (b != null)
return b;
// Download image file from web
try {
// // download the image
Bitmap bitmap = null;
URL imageURL = null;
try {
imageURL = new URL(Config.WEB_URL + "/ServeBlob?id=" + url);
HttpURLConnection connection = (HttpURLConnection) imageURL
.openConnection();
connection.setDoInput(true);
connection.connect();
// if(!(new File(imageURL.toString())).exists())
// {
// imageURL=new URL("");
// }
InputStream inputStream = connection.getInputStream();
// Constructs a new FileOutputStream that writes to
// file
// if file not exist then it will create file
OutputStream os = new FileOutputStream(f);
// See Utils class CopyStream method
// It will each pixel from input stream and
// write pixels to output stream (file)
Utils.CopyStream(inputStream, os);
os.close();
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 8;
bitmap = BitmapFactory.decodeStream(inputStream, null, options);
} catch (IOException e) {
// e.printStackTrace();
}
// Now file created and going to resize file with defined height
// Decodes image and scales it to reduce memory consumption
bitmap = decodeFile(f);
return bitmap;
} catch (Throwable ex) {
ex.printStackTrace();
if (ex instanceof OutOfMemoryError)
memoryCache.clear();
return null;
}
}
// Decodes image and scales it to reduce memory consumption
private Bitmap decodeFile(File f) {
try {
// Decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
FileInputStream stream1 = new FileInputStream(f);
BitmapFactory.decodeStream(stream1, null, o);
stream1.close();
// Find the correct scale value. It should be the power of 2.
// Set width/height of recreated image
final int REQUIRED_SIZE = 85;
int width_tmp = o.outWidth, height_tmp = o.outHeight;
int scale = 1;
while (true) {
if (width_tmp / 2 < REQUIRED_SIZE
|| height_tmp / 2 < REQUIRED_SIZE)
break;
width_tmp /= 2;
height_tmp /= 2;
scale *= 2;
}
// decode with current scale values
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize = scale;
FileInputStream stream2 = new FileInputStream(f);
Bitmap bitmap = BitmapFactory.decodeStream(stream2, null, o2);
stream2.close();
return bitmap;
} catch (FileNotFoundException e) {
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
boolean imageViewReused(PhotoToLoad photoToLoad) {
String tag = imageViews.get(photoToLoad.imageView);
// Check url is already exist in imageViews MAP
if (tag == null || !tag.equals(photoToLoad.url))
return true;
return false;
}
// Used to display bitmap in the UI thread
class BitmapDisplayer implements Runnable {
Bitmap bitmap;
PhotoToLoad photoToLoad;
public BitmapDisplayer(Bitmap b, PhotoToLoad p) {
bitmap = b;
photoToLoad = p;
}
public void run() {
if (imageViewReused(photoToLoad))
return;
// Show bitmap on UI
if (bitmap != null) {
photoToLoad.imageView.setImageBitmap(ScaleBitmap
.getScaledBitmap(C, bitmap, photoToLoad.b));
} else {
}
// photoToLoad.imageView.setImageResource(stub_id);
}
}
public void clearCache() {
// Clear cache directory downloaded images and stored data in maps
memoryCache.clear();
fileCache.clear();
}
}
package com.fudiyoxpress.images;
import Java.util.Collections;
import Java.util.Iterator;
import Java.util.LinkedHashMap;
import Java.util.Map;
import Java.util.Map.Entry;
import Android.graphics.Bitmap;
import Android.util.Log;
public class MemoryCache {
private static final String TAG = "MemoryCache";
//Last argument true for LRU ordering
private Map<String, Bitmap> cache = Collections.synchronizedMap(
new LinkedHashMap<String, Bitmap>(10,1.5f,true));
//current allocated size
private long size=0;
//max memory cache folder used to download images in bytes
private long limit = 1000000;
public MemoryCache(){
//use 25% of available heap size
setLimit(Runtime.getRuntime().maxMemory()/4);
}
public void setLimit(long new_limit){
limit=new_limit;
Log.i(TAG, "MemoryCache will use up to "+limit/1024./1024.+"MB");
}
public Bitmap get(String id){
try{
if(!cache.containsKey(id))
return null;
//NullPointerException sometimes happen here http://code.google.com/p/osmdroid/issues/detail?id=78
return cache.get(id);
}catch(NullPointerException ex){
ex.printStackTrace();
return null;
}
}
public void put(String id, Bitmap bitmap){
try{
if(cache.containsKey(id))
size-=getSizeInBytes(cache.get(id));
cache.put(id, bitmap);
size+=getSizeInBytes(bitmap);
checkSize();
}catch(Throwable th){
th.printStackTrace();
}
}
private void checkSize() {
Log.i(TAG, "cache size="+size+" length="+cache.size());
if(size>limit){
Iterator<Entry<String, Bitmap>> iter=cache.entrySet().iterator();//least recently accessed item will be the first one iterated
while(iter.hasNext()){
Entry<String, Bitmap> entry=iter.next();
size-=getSizeInBytes(entry.getValue());
iter.remove();
if(size<=limit)
break;
}
Log.i(TAG, "Clean cache. New size "+cache.size());
}
}
public void clear() {
try{
//NullPointerException sometimes happen here http://code.google.com/p/osmdroid/issues/detail?id=78
cache.clear();
size=0;
}catch(NullPointerException ex){
ex.printStackTrace();
}
}
long getSizeInBytes(Bitmap bitmap) {
if(bitmap==null)
return 0;
return bitmap.getRowBytes() * bitmap.getHeight();
}
}
package com.fudiyoxpress.images;
import Java.io.InputStream;
import Java.io.OutputStream;
public class Utils {
public static void CopyStream(InputStream is, OutputStream os)
{
final int buffer_size=1024;
try
{
byte[] bytes=new byte[buffer_size];
for(;;)
{
//Read byte from input stream
int count=is.read(bytes, 0, buffer_size);
if(count==-1)
break;
//Write byte from output stream
os.write(bytes, 0, count);
}
}
catch(Exception ex){}
}
}
あなたは効果的な遅延ロードのためにPiccaso
やVolley
のようなサードパーティのライブラリを使うことができます。以下を実装することであなた自身のものを作ることもできます
URLから画像をダウンロードするためのコードを実装する
画像を保存および取得するためのキャッシュメカニズムを実装する(キャッシュにはAndroidのLruCache
を使用します)
私は Glide をPicasso
よりも良いオプションとして見つけました。私はpicassoを使用して、それぞれ32
のサイズの200-500KB
イメージをロードし、常にOOM
を取得していました。しかしGlide
は私のすべてのOOM
の問題を解決しました。
あなたはGreenDroidのAsyncImageViewを使うことができます。 setUrlを呼び出すだけで、これはあなたがしたいことをするのに役立つかもしれないし、以下に与えられているこのリンクを参照すること:
データキャッシュを非同期的にロードする場合を除き、UIキャッシュが必要な場合があります。
表示項目データのロードを除いて、近似表示項目データのロードが必要になる場合があります。
例:リストビューの目に見える項目が[6,7,8,9,10]であると仮定すると、[6,7,8,9,10]をロードして項目[1、2、3、4]を事前にロードする必要があります、5]&[11、12、13、14、15]、ユーザーはおそらくプリページまたはポストページにスクロールするため