回答:
そして今、パンチライン:システムキャッシュを使用します。
URL url = new URL(strUrl);
URLConnection connection = url.openConnection();
connection.setUseCaches(true);
Object response = connection.getContent();
if (response instanceof Bitmap) {
Bitmap bitmap = (Bitmap)response;
}
ブラウザと共有するメモリとフラッシュROMキャッシュの両方を提供します。
grr。誰かが私に自分のキャッシュマネージャーを書く前に私に言ってくれたらよかったのに。
connection.getContent()
常に私のためにInputStreamを返します、何が間違っていますか?
Bitmap response = BitmapFactory.decodeStream((InputStream)connection.getContent());
connection.setUseCaches
上記のエレガントなソリューションについて:悲しいことに、それは追加の努力なしでは機能しません。ResponseCache
を使用してインストールする必要がありResponseCache.setDefault
ます。それ以外の場合、HttpURLConnection
黙ってsetUseCaches(true)
ビットを無視します。
詳細については、上部のコメントを参照してFileResponseCache.java
ください。
(私はこれをコメントで投稿しますが、明らかに十分なカルマがありません。)
HttpResponseCache
、HttpResponseCache.getHitCount()
0 が返されることがあります。よくわかりませんが、これは、リクエストしているWebサーバーがキャッシュヘッダーを使用していないためだと思います。とにかくキャッシュを機能させるには、を使用しますconnection.addRequestProperty("Cache-Control", "max-stale=" + MAX_STALE_CACHE);
。
.getContent()
メソッドの使用時にHUCがハングします。これは、304応答にはRFC標準による関連付けられた応答本文がないためです。
それらをビットマップに変換し、コレクション(ハッシュマップ、リストなど)に保存するか、SDカードに書き込むことができます。
最初のアプローチを使用してそれらをアプリケーションスペースに格納する場合、特にそれらの数が大きい場合は、java.lang.ref.SoftReferenceにそれらをラップすることをお勧めします(そのため、危機時にガベージコレクションされます)。ただし、これにより再読み込みが発生する可能性があります。
HashMap<String,SoftReference<Bitmap>> imageCache =
new HashMap<String,SoftReference<Bitmap>>();
SDカードにそれらを書き込むことはリロードを必要としません。ユーザー権限のみ。
Uri
パス参照ImageView
や他のカスタムビューを取得することをお勧めします。毎回compress
、あなたは品質を失うことになるからです。もちろん、これは非可逆アルゴリズムにのみ当てはまります。このメソッドは、あなたもあなたを介してサーバからファイルを要求次回のファイルのハッシュを格納し、それを使用できるようになるIf-None-Match
とETag
ヘッダを。
LruCache
画像を効率的にキャッシュするために使用します。Android開発者サイトLruCache
から読むことができます
私は画像のダウンロードとAndroidでのキャッシュのために以下のソリューションを使用しました。以下の手順に従ってください。
ステップ1:
クラスを名前付きにするImagesCache
。私は使いましたSingleton object for this class
import android.graphics.Bitmap;
import android.support.v4.util.LruCache;
public class ImagesCache
{
private LruCache<String, Bitmap> imagesWarehouse;
private static ImagesCache cache;
public static ImagesCache getInstance()
{
if(cache == null)
{
cache = new ImagesCache();
}
return cache;
}
public void initializeCache()
{
final int maxMemory = (int) (Runtime.getRuntime().maxMemory() /1024);
final int cacheSize = maxMemory / 8;
System.out.println("cache size = "+cacheSize);
imagesWarehouse = new LruCache<String, Bitmap>(cacheSize)
{
protected int sizeOf(String key, Bitmap value)
{
// The cache size will be measured in kilobytes rather than number of items.
int bitmapByteCount = value.getRowBytes() * value.getHeight();
return bitmapByteCount / 1024;
}
};
}
public void addImageToWarehouse(String key, Bitmap value)
{
if(imagesWarehouse != null && imagesWarehouse.get(key) == null)
{
imagesWarehouse.put(key, value);
}
}
public Bitmap getImageFromWarehouse(String key)
{
if(key != null)
{
return imagesWarehouse.get(key);
}
else
{
return null;
}
}
public void removeImageFromWarehouse(String key)
{
imagesWarehouse.remove(key);
}
public void clearCache()
{
if(imagesWarehouse != null)
{
imagesWarehouse.evictAll();
}
}
}
ステップ2:
キャッシュでビットマップが使用できない場合に使用されるDownloadImageTaskという名前の別のクラスを作成します。ここからダウンロードします。
public class DownloadImageTask extends AsyncTask<String, Void, Bitmap>
{
private int inSampleSize = 0;
private String imageUrl;
private BaseAdapter adapter;
private ImagesCache cache;
private int desiredWidth, desiredHeight;
private Bitmap image = null;
private ImageView ivImageView;
public DownloadImageTask(BaseAdapter adapter, int desiredWidth, int desiredHeight)
{
this.adapter = adapter;
this.cache = ImagesCache.getInstance();
this.desiredWidth = desiredWidth;
this.desiredHeight = desiredHeight;
}
public DownloadImageTask(ImagesCache cache, ImageView ivImageView, int desireWidth, int desireHeight)
{
this.cache = cache;
this.ivImageView = ivImageView;
this.desiredHeight = desireHeight;
this.desiredWidth = desireWidth;
}
@Override
protected Bitmap doInBackground(String... params)
{
imageUrl = params[0];
return getImage(imageUrl);
}
@Override
protected void onPostExecute(Bitmap result)
{
super.onPostExecute(result);
if(result != null)
{
cache.addImageToWarehouse(imageUrl, result);
if(ivImageView != null)
{
ivImageView.setImageBitmap(result);
}
else if(adapter != null)
{
adapter.notifyDataSetChanged();
}
}
}
private Bitmap getImage(String imageUrl)
{
if(cache.getImageFromWarehouse(imageUrl) == null)
{
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
options.inSampleSize = inSampleSize;
try
{
URL url = new URL(imageUrl);
HttpURLConnection connection = (HttpURLConnection)url.openConnection();
InputStream stream = connection.getInputStream();
image = BitmapFactory.decodeStream(stream, null, options);
int imageWidth = options.outWidth;
int imageHeight = options.outHeight;
if(imageWidth > desiredWidth || imageHeight > desiredHeight)
{
System.out.println("imageWidth:"+imageWidth+", imageHeight:"+imageHeight);
inSampleSize = inSampleSize + 2;
getImage(imageUrl);
}
else
{
options.inJustDecodeBounds = false;
connection = (HttpURLConnection)url.openConnection();
stream = connection.getInputStream();
image = BitmapFactory.decodeStream(stream, null, options);
return image;
}
}
catch(Exception e)
{
Log.e("getImage", e.toString());
}
}
return image;
}
ステップ3:Activity
またはからの使用Adapter
注意:Activity
クラスのURLから画像をロードする場合。の2番目のコンストラクタを使用しますが、最初のコンストラクタを使用DownloadImageTask
して画像を表示したい場合(たとえば、画像があり、「アダプタ」から画像を設定している場合)Adapter
DownloadImageTask
ListView
アクティビティからの使用:
ImageView imv = (ImageView) findViewById(R.id.imageView);
ImagesCache cache = ImagesCache.getInstance();//Singleton instance handled in ImagesCache class.
cache.initializeCache();
String img = "your_image_url_here";
Bitmap bm = cache.getImageFromWarehouse(img);
if(bm != null)
{
imv.setImageBitmap(bm);
}
else
{
imv.setImageBitmap(null);
DownloadImageTask imgTask = new DownloadImageTask(cache, imv, 300, 300);//Since you are using it from `Activity` call second Constructor.
imgTask.execute(img);
}
アダプターからの使用:
ImageView imv = (ImageView) rowView.findViewById(R.id.imageView);
ImagesCache cache = ImagesCache.getInstance();
cache.initializeCache();
String img = "your_image_url_here";
Bitmap bm = cache.getImageFromWarehouse(img);
if(bm != null)
{
imv.setImageBitmap(bm);
}
else
{
imv.setImageBitmap(null);
DownloadImageTask imgTask = new DownloadImageTask(this, 300, 300);//Since you are using it from `Adapter` call first Constructor.
imgTask.execute(img);
}
注意:
cache.initializeCache()
このステートメントは、アプリケーションの最初のアクティビティで使用できます。キャッシュを初期化したら、使用している場合は毎回キャッシュを初期化する必要はありません。ImagesCache
インスタンス場合。
私は物事を説明するのが得意ではありませんが、これが初心者が LruCache
とその使用法ています:)
編集:
今日は、として知られている非常に有名なライブラリがあるPicasso
とGlide
Androidアプリで非常に効率的に負荷の画像に使用することができます。この非常にシンプルで便利なライブラリPicasso for androidとGlide For Androidをお試しください。キャッシュイメージについて心配する必要はありません。
Picassoを使用すると、アプリケーションに手間をかけずに画像を読み込むことができます。多くの場合、1行のコードで読み込みます。
Glideは、Picassoと同じように、多くのソースから画像を読み込んで表示することができます。また、画像の操作を行う際にキャッシュを処理し、メモリへの影響を低く抑えます。公式のGoogleアプリ(Google I / O 2015用アプリなど)で使用されており、ピカソと同じくらい人気があります。このシリーズでは、ピカソに対するグライドの違いと利点を探ります。
グライドとピカソの違いについてはブログをご覧ください
if(cache == null)
私の問題を解決したことに賛成してください!:)
画像をダウンロードしてメモリカードに保存するには、次のようにします。
//First create a new URL object
URL url = new URL("http://www.google.co.uk/logos/holiday09_2.gif")
//Next create a file, the example below will save to the SDCARD using JPEG format
File file = new File("/sdcard/example.jpg");
//Next create a Bitmap object and download the image to bitmap
Bitmap bitmap = BitmapFactory.decodeStream(url.openStream());
//Finally compress the bitmap, saving to the file previously created
bitmap.compress(CompressFormat.JPEG, 100, new FileOutputStream(file));
マニフェストにインターネット許可を追加することを忘れないでください:
<uses-permission android:name="android.permission.INTERNET" />
droidfuの画像キャッシュの使用を検討します。インメモリとディスクベースの両方の画像キャッシュを実装します。また、ImageCacheライブラリを利用するWebImageViewも取得します。
ここdroidfuの完全な記述があるとWebImageView: http://brainflush.wordpress.com/2009/11/23/droid-fu-part-2-webimageview-and-webgalleryadapter/
サンダーラビットが示唆したように、ImageDownloaderは仕事に最適です。私はまた、クラスのわずかなバリエーションを見つけました:
http://theandroidcoder.com/utilities/android-image-download-and-caching/
2つの主な違いは、ImageDownloaderがAndroidキャッシングシステムを使用し、変更されたものは内部および外部ストレージをキャッシングとして使用することです。著者は、Android 2.1の互換性についても言及しています。
これはジョーの良いキャッチです。上記のコード例には2つの問題があります-1つ-応答オブジェクトがビットマップのインスタンスではありません(私のURLがhttp:\ website.com \ image.jpgのようなjpgを参照する場合、
org.apache.harmony.luni.internal.net.www.protocol.http.HttpURLConnectionImpl $ LimitedInputStream)。
次に、Joeが指摘するように、応答キャッシュが構成されていないと、キャッシュは発生しません。Android開発者は自分のキャッシュをロールバックする必要があります。これはそのための例ですが、メモリにキャッシュするだけで、完全なソリューションではありません。
http://codebycoffee.com/2010/06/29/using-responsecache-in-an-android-app/
ここでは、URLConnectionキャッシングAPIについて説明します。
http://download.oracle.com/javase/6/docs/technotes/guides/net/http-cache.html
私はまだこれがこのルートに進むためのOKソリューションであると思います-しかし、あなたはまだキャッシュを書かなければなりません。楽しそうに聞こえますが、機能を記述したいのですが。
これについては、Androidの公式トレーニングセクションに特別なエントリがあります。 ます。http //developer.android.com/training/displaying-bitmaps/cache-bitmap.html
このセクションはかなり新しいもので、質問されたときにそこにはありませんでした。
推奨される解決策は、LruCacheを使用することです。そのクラスはHoneycombで導入されましたが、互換性ライブラリにも含まれています。
最大数またはエントリを設定することでLruCacheを初期化できます。制限を超えると、LruCacheによって自動的にソートされ、使用頻度の低いものはクリーンアップされます。それ以外は通常の地図として使用されます。
公式ページのサンプルコード:
private LruCache mMemoryCache;
@Override
protected void onCreate(Bundle savedInstanceState) {
...
// Get memory class of this device, exceeding this amount will throw an
// OutOfMemory exception.
final int memClass = ((ActivityManager) context.getSystemService(
Context.ACTIVITY_SERVICE)).getMemoryClass();
// Use 1/8th of the available memory for this memory cache.
final int cacheSize = 1024 * 1024 * memClass / 8;
mMemoryCache = new LruCache(cacheSize) {
@Override
protected int sizeOf(String key, Bitmap bitmap) {
// The cache size will be measured in bytes rather than number of items.
return bitmap.getByteCount();
}
};
...
}
public void addBitmapToMemoryCache(String key, Bitmap bitmap) {
if (getBitmapFromMemCache(key) == null) {
mMemoryCache.put(key, bitmap);
}
}
public Bitmap getBitmapFromMemCache(String key) {
return mMemoryCache.get(key);
}
以前はSoftReferencesは良い代替手段でしたが、公式ページから引用すると、もはやそうではありません。
注:以前は、人気のあるメモリキャッシュ実装はSoftReferenceまたはWeakReferenceビットマップキャッシュでしたが、これはお勧めできません。Android 2.3(APIレベル9)以降、ガベージコレクターは、ソフト/弱い参照を収集することでより積極的になり、かなり無効になっています。さらに、Android 3.0(APIレベル11)より前のバージョンでは、ビットマップのバッキングデータはネイティブメモリに格納されていたため、予測可能な方法で解放されず、アプリケーションがメモリ制限を一時的に超えてクラッシュする可能性がありました。
Sergey TarasevichによるUniversal Image Loaderライブラリの使用を検討してください。付属しています:
Universal Image Loaderは、以下のキャッシュ構成で、ダウンロードされたイメージの詳細なキャッシュ管理を可能にします。
UsingFreqLimitedMemoryCache
:キャッシュサイズの制限を超えると、使用頻度の最も低いビットマップが削除されます。LRULimitedMemoryCache
:キャッシュサイズの制限を超えると、最も使用頻度の低いビットマップが削除されます。FIFOLimitedMemoryCache
:FIFOルールは、キャッシュサイズの制限を超えた場合の削除に使用されます。LargestLimitedMemoryCache
:キャッシュサイズの制限を超えると、最大のビットマップが削除されます。LimitedAgeMemoryCache
:キャッシュされたオブジェクトは、その経過時間が定義された値を超えると削除されます。WeakMemoryCache
:ビットマップへの弱い参照のみを持つメモリキャッシュ。簡単な使用例:
ImageView imageView = groupView.findViewById(R.id.imageView);
String imageUrl = "http://site.com/image.png";
ImageLoader imageLoader = ImageLoader.getInstance();
imageLoader.init(ImageLoaderConfiguration.createDefault(context));
imageLoader.displayImage(imageUrl, imageView);
この例では、デフォルトを使用していますUsingFreqLimitedMemoryCache
。
実際に機能したのは、メインクラスにResponseCacheを設定することでした。
try {
File httpCacheDir = new File(getApplicationContext().getCacheDir(), "http");
long httpCacheSize = 10 * 1024 * 1024; // 10 MiB
HttpResponseCache.install(httpCacheDir, httpCacheSize);
} catch (IOException e) { }
そして
connection.setUseCaches(true);
ビットマップをダウンロードするとき。
http://practicaldroid.blogspot.com/2013/01/utilizing-http-response-cache.html
Googleのlibs-for-androidには、画像とファイルのキャッシュを管理するための素晴らしいライブラリがあります。
私はしばらくこれに取り組んできました。SoftReferencesを使用した回答では、データがすぐに失われます。RequestCacheをインスタンス化することを示唆する回答は、あまりにも複雑で、完全な例を見つけることはできませんでした。
しかし、ImageDownloader.javaは私にとって素晴らしい働きをします。容量に到達するまで、またはパージタイムアウトが発生するまでHashMapを使用します。その後、物事はSoftReferenceに移動し、それによって両方の長所を使用します。
私が提案するIGNITIONを、これはドロイドFUよりも優れています
https://github.com/kaeppler/ignition
https://github.com/kaeppler/ignition/wiki/Sample-applications
後で答えますが、キャッシュ(メモリとディスク)を透過的に処理するAndroid Image Managerを作成しました。コードはGithub https://github.com/felipecsl/Android-ImageManagerにあります
後期の答えが、私は、私はアンドロイドのためのイメージキャッシュを作成する方法のチュートリアルを書かれているので、私は自分のサイトへのリンクを追加する必要があります考え出し:http://squarewolf.nl/2010/11/android-image-cache/ アップデート:ソースが古くなっているため、ページはオフラインになっています。Ignitionを使用するためのアドバイスとして@elenasysに参加します。
この質問に遭遇し、解決策を見つけていないすべての人に、楽しんでください!= D
遅い答えですが、このライブラリは画像のキャッシングに非常に役立つと思います:https : //github.com/crypticminds/ColdStorage。
@LoadCache(R.id.id_of_my_image_view、 "URL_to_downlaod_image_from)でImageViewに注釈を付けるだけで、画像のダウンロードと画像ビューへの読み込みが処理されます。プレースホルダー画像と読み込みアニメーションを指定することもできます。
アノテーションの詳細なドキュメントはここにあります:-https : //github.com/crypticminds/ColdStorage/wiki/@LoadImage-annotation