Antworten:
Und jetzt die Pointe: Verwenden Sie den System-Cache.
URL url = new URL(strUrl);
URLConnection connection = url.openConnection();
connection.setUseCaches(true);
Object response = connection.getContent();
if (response instanceof Bitmap) {
Bitmap bitmap = (Bitmap)response;
}
Bietet sowohl Speicher als auch Flash-ROM-Cache, die für den Browser freigegeben sind.
grr. Ich wünschte, jemand hätte mir das gesagt, bevor ich meinen eigenen Cache-Manager schrieb.
connection.getContent()
Gibt immer einen InputStream für mich zurück. Was mache ich falsch?
Bitmap response = BitmapFactory.decodeStream((InputStream)connection.getContent());
In Bezug auf die elegante connection.setUseCaches
Lösung oben: Leider funktioniert es nicht ohne zusätzlichen Aufwand. Sie müssen eine ResponseCache
using installieren ResponseCache.setDefault
. Andernfalls HttpURLConnection
wird das setUseCaches(true)
Bit stillschweigend ignoriert .
Weitere FileResponseCache.java
Informationen finden Sie in den Kommentaren oben auf:
(Ich würde dies in einem Kommentar posten, aber ich habe anscheinend nicht genug SO-Karma.)
HttpResponseCache
, finden Sie möglicherweise die HttpResponseCache.getHitCount()
Rückgabe 0. Ich bin nicht sicher, aber ich denke, das liegt daran, dass der von Ihnen angeforderte Webserver in diesem Fall keine Caching-Header verwendet. Verwenden Sie, um das Caching trotzdem zum Laufen zu bringen connection.addRequestProperty("Cache-Control", "max-stale=" + MAX_STALE_CACHE);
.
.getContent()
Methode verwendet wird, da 304 Antworten nach RFC-Standard kein Antworttext zugeordnet ist.
Konvertieren Sie sie in Bitmaps und speichern Sie sie entweder in einer Sammlung (HashMap, Liste usw.) oder Sie können sie auf die SD-Karte schreiben.
Wenn Sie sie mit dem ersten Ansatz im Anwendungsbereich speichern, möchten Sie sie möglicherweise um eine java.lang.ref.SoftReference wickeln, insbesondere wenn ihre Anzahl groß ist (damit sie während der Krise als Müll gesammelt werden). Dies könnte jedoch zu einem Neuladen führen.
HashMap<String,SoftReference<Bitmap>> imageCache =
new HashMap<String,SoftReference<Bitmap>>();
Für das Schreiben auf eine SD-Karte ist kein erneutes Laden erforderlich. nur eine Benutzerberechtigung.
Uri
Pfadreferenz zu erhalten, an die Sie übergeben können, ImageView
sowie andere benutzerdefinierte Ansichten. Denn jedes Mal compress
verlieren Sie an Qualität. Dies gilt natürlich nur für verlustbehaftete Algorithmen. Mit dieser Methode können Sie auch einen Hash der Datei speichern und beim nächsten Anfordern der Datei vom Server über If-None-Match
und in den ETag
Headern verwenden.
Verwenden Sie LruCache
diese Option, um Bilder effizient zwischenzuspeichern. Sie können über LruCache
von Android Developer Site lesen
Ich habe unten Lösung für das Herunterladen und Zwischenspeichern von Bildern in Android verwendet. Sie können die folgenden Schritte ausführen:
SCHRITT 1:
Klasse benennen ImagesCache
. Ich habe benutztSingleton 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();
}
}
}
SCHRITT 2:
Erstellen Sie eine andere Klasse mit dem Namen DownloadImageTask, die verwendet wird, wenn die Bitmap nicht im Cache verfügbar ist. Sie wird von hier heruntergeladen:
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;
}
SCHRITT 3: Verwendung von Ihrem Activity
oderAdapter
Hinweis: Wenn Sie ein Bild von einer URL aus der Activity
Klasse laden möchten . Verwenden Sie den zweiten Konstruktor vonDownloadImageTask
, aber wenn Sie ein Bild anzeigen möchten, Adapter
verwenden Sie den ersten Konstruktor von DownloadImageTask
(zum Beispiel haben Sie ein Bild in ListView
und setzen das Bild von 'Adapter').
NUTZUNG AUS DER AKTIVITÄT:
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);
}
VERWENDUNG VOM ADAPTER:
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);
}
Hinweis:
cache.initializeCache()
Sie können diese Anweisung in der allerersten Aktivität Ihrer Anwendung verwenden. Sobald Sie den Cache initialisiert haben, müssen Sie ihn nie mehr jedes Mal initialisieren, wenn Sie eine ImagesCache
Instanz verwenden.
Ich bin nie gut darin, Dinge zu erklären, aber ich hoffe, dies wird den Anfängern helfen, wie man die Verwendung LruCache
und ihre Verwendung zwischenspeichert :)
BEARBEITEN:
Heute gibt es sehr berühmte Bibliotheken, die als Picasso
und bekannt Glide
sind, um Bilder sehr effizient in Android App zu laden. Probieren Sie diese sehr einfache und nützliche Bibliothek Picasso für Android und Glide für Android . Sie müssen sich keine Gedanken über Cache-Bilder machen.
Picasso ermöglicht das problemlose Laden von Bildern in Ihre Anwendung - häufig in einer Codezeile!
Glide kann genau wie Picasso Bilder aus vielen Quellen laden und anzeigen, während gleichzeitig das Zwischenspeichern und die geringe Auswirkung auf den Speicher bei Bildmanipulationen berücksichtigt werden. Es wurde von offiziellen Google Apps (wie der App für Google I / O 2015) verwendet und ist genauso beliebt wie Picasso. In dieser Serie werden wir die Unterschiede und Vorteile von Glide gegenüber Picasso untersuchen.
Sie können auch den Blog besuchen, um den Unterschied zwischen Glide und Picasso zu erfahren
if(cache == null)
was mein Problem gelöst hat! :)
Um ein Bild herunterzuladen und auf der Speicherkarte zu speichern, können Sie dies folgendermaßen tun.
//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));
Vergessen Sie nicht, Ihrem Manifest die Internetberechtigung hinzuzufügen:
<uses-permission android:name="android.permission.INTERNET" />
Ich würde in Betracht ziehen, den Bildcache von droidfu zu verwenden. Es implementiert sowohl einen speicherinternen als auch einen festplattenbasierten Image-Cache. Sie erhalten auch eine WebImageView, die die ImageCache-Bibliothek nutzt.
Hier ist die vollständige Beschreibung von droidfu und WebImageView: http://brainflush.wordpress.com/2009/11/23/droid-fu-part-2-webimageview-and-webgalleryadapter/
Ich habe SoftReferences ausprobiert, sie werden in Android zu aggressiv zurückgefordert, als dass ich der Meinung wäre, dass es keinen Sinn macht, sie zu verwenden
SoftReference
s sehr aggressiv ist . Sie empfehlen stattdessen ihre LruCache
.
Wie Thunder Rabbit vorgeschlagen hat, ist ImageDownloader der beste für diesen Job. Ich fand auch eine leichte Variation der Klasse bei:
http://theandroidcoder.com/utilities/android-image-download-and-caching/
Der Hauptunterschied zwischen beiden besteht darin, dass der ImageDownloader das Android-Caching-System verwendet und der modifizierte den internen und externen Speicher als Caching verwendet, wobei die zwischengespeicherten Bilder unbegrenzt bleiben oder bis der Benutzer sie manuell entfernt. Der Autor erwähnt auch die Kompatibilität mit Android 2.1.
Dies ist ein guter Fang von Joe. Das obige Codebeispiel hat zwei Probleme - eines - das Antwortobjekt ist keine Instanz von Bitmap (wenn meine URL auf ein JPG verweist, wie z. B. http: \ website.com \ image.jpg, ist es ein
org.apache.harmony.luni.internal.net.www.protocol.http.HttpURLConnectionImpl $ LimitedInputStream).
Zweitens, wie Joe betont, findet kein Caching statt, ohne dass ein Antwortcache konfiguriert ist. Android-Entwickler müssen ihren eigenen Cache rollen. Hier ist ein Beispiel dafür, aber es werden nur im Speicher zwischengespeichert, was wirklich nicht die vollständige Lösung ist.
http://codebycoffee.com/2010/06/29/using-responsecache-in-an-android-app/
Die URLConnection-Caching-API wird hier beschrieben:
http://download.oracle.com/javase/6/docs/technotes/guides/net/http-cache.html
Ich denke immer noch, dass dies eine gute Lösung ist, um diesen Weg zu gehen - aber Sie müssen immer noch einen Cache schreiben. Klingt nach Spaß, aber ich würde lieber Features schreiben.
Es gibt einen speziellen Eintrag im offiziellen Trainingsbereich von Android dazu: http://developer.android.com/training/displaying-bitmaps/cache-bitmap.html
Der Abschnitt ist ziemlich neu, er war nicht da, als die Frage gestellt wurde.
Die vorgeschlagene Lösung ist die Verwendung eines LruCache. Diese Klasse wurde in Honeycomb eingeführt, ist aber auch in der Kompatibilitätsbibliothek enthalten.
Sie können einen LruCache initialisieren, indem Sie die maximale Anzahl oder die maximalen Einträge festlegen. Diese sortieren sie automatisch nach Ihren Wünschen und bereinigen weniger verwendete Einträge, wenn Sie das Limit überschreiten. Ansonsten wird es als normale Karte verwendet.
Der Beispielcode von der offiziellen Seite:
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);
}
Bisher waren SoftReferences eine gute Alternative, aber nicht mehr, zitiert von der offiziellen Seite:
Hinweis: In der Vergangenheit war eine beliebte Implementierung des Speichercaches ein SoftReference- oder WeakReference-Bitmap-Cache. Dies wird jedoch nicht empfohlen. Ab Android 2.3 (API Level 9) ist der Garbage Collector aggressiver beim Sammeln von weichen / schwachen Referenzen, was sie ziemlich ineffektiv macht. Darüber hinaus wurden vor Android 3.0 (API Level 11) die Sicherungsdaten einer Bitmap im nativen Speicher gespeichert, der nicht vorhersehbar freigegeben wurde. Dies kann dazu führen, dass eine Anwendung kurzzeitig ihre Speichergrenzen überschreitet und abstürzt.
Erwägen Sie die Verwendung der Universal Image Loader-Bibliothek von Sergey Tarasevich . Es kommt mit:
Universal Image Loader ermöglicht eine detaillierte Cache-Verwaltung für heruntergeladene Bilder mit den folgenden Cache-Konfigurationen:
UsingFreqLimitedMemoryCache
: Die am seltensten verwendete Bitmap wird gelöscht, wenn die Cache-Größenbeschränkung überschritten wird.LRULimitedMemoryCache
: Das zuletzt verwendete Bitmap wird gelöscht, wenn die Cache-Größenbeschränkung überschritten wird.FIFOLimitedMemoryCache
: Die FIFO-Regel wird zum Löschen verwendet, wenn die Cache-Größenbeschränkung überschritten wird.LargestLimitedMemoryCache
: Das größte Bitmap wird gelöscht, wenn die Cache-Größenbeschränkung überschritten wird.LimitedAgeMemoryCache
: Das zwischengespeicherte Objekt wird gelöscht, wenn es Alter den definierten Wert überschreitet .WeakMemoryCache
: Ein Speichercache mit nur schwachen Verweisen auf Bitmaps.Ein einfaches Anwendungsbeispiel:
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);
In diesem Beispiel wird die Standardeinstellung verwendet UsingFreqLimitedMemoryCache
.
Was für mich tatsächlich funktionierte, war das Festlegen von ResponseCache für meine Hauptklasse:
try {
File httpCacheDir = new File(getApplicationContext().getCacheDir(), "http");
long httpCacheSize = 10 * 1024 * 1024; // 10 MiB
HttpResponseCache.install(httpCacheDir, httpCacheSize);
} catch (IOException e) { }
und
connection.setUseCaches(true);
beim Herunterladen der Bitmap.
http://practicaldroid.blogspot.com/2013/01/utilizing-http-response-cache.html
Googles libs-for-android verfügt über nette Bibliotheken zum Verwalten des Bild- und Dateicaches.
Ich hatte seit einiger Zeit damit gerungen; Die Antworten mit SoftReferences würden ihre Daten zu schnell verlieren. Die Antworten, die darauf hindeuten, einen RequestCache zu instanziieren, waren zu chaotisch, und ich konnte nie ein vollständiges Beispiel finden.
Aber ImageDownloader.java funktioniert wunderbar für mich. Es wird eine HashMap verwendet, bis die Kapazität erreicht ist oder bis das Zeitlimit für die Bereinigung auftritt. Anschließend werden die Dinge in eine SoftReference verschoben, wodurch das Beste aus beiden Welten verwendet wird.
Ich schlage ZÜNDUNG vor, dies ist sogar besser als Droid Fu
https://github.com/kaeppler/ignition
https://github.com/kaeppler/ignition/wiki/Sample-applications
Noch später antworten, aber ich habe einen Android Image Manager geschrieben, der das Caching transparent (Speicher und Festplatte) handhabt. Der Code befindet sich auf Github https://github.com/felipecsl/Android-ImageManager
Späte Antwort, aber ich dachte mir, ich sollte einen Link zu meiner Site hinzufügen, da ich ein Tutorial geschrieben habe, wie man einen Bildcache für Android erstellt: http://squarewolf.nl/2010/11/android-image-cache/ Update: the Die Seite wurde offline geschaltet, da die Quelle veraltet war. Ich schließe mich @elenasys in ihrem Rat an, Ignition zu verwenden .
Also an alle Leute, die über diese Frage stolpern und keine Lösung gefunden haben: Ich hoffe es gefällt euch! = D.
Späte Antwort, aber ich denke, diese Bibliothek wird beim Zwischenspeichern von Bildern sehr hilfreich sein: https://github.com/crypticminds/ColdStorage .
Kommentieren Sie die ImageView einfach mit @LoadCache (R.id.id_of_my_image_view, "URL_to_downlaod_image_from"). Das Bild wird heruntergeladen und in die Bildansicht geladen. Sie können auch ein Platzhalterbild angeben und eine Animation laden.
Eine ausführliche Dokumentation der Anmerkung finden Sie hier: - https://github.com/crypticminds/ColdStorage/wiki/@LoadImage-annotation