Wie kann ich Bilder zwischenspeichern, nachdem sie aus dem Internet heruntergeladen wurden?
Zwischenspeichern von Android-Bildern
D-Mann
edrowland
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;
}
Stellt sowohl Arbeitsspeicher als auch Flash-ROM-Cache bereit, die mit dem Browser geteilt werden.
grr. Ich wünschte, jemand hätte MIR das gesagt, bevor ich meinen eigenen Cache-Manager geschrieben habe.
-
Wow, das war eine unglaublich elegante Art, dies zu tun, vielen Dank. Es ist in keiner Weise langsamer als mein eigener einfacher Cache-Manager, und jetzt muss ich mich nicht mehr um einen SD-Kartenordner kümmern.
– Kevin Lesen
16. Oktober 2010 um 20:44 Uhr
-
connection.getContent()
gibt mir immer einen InputStream zurück, was mache ich falsch?– Tyler Collier
7. Juli 2011 um 18:36 Uhr
-
Wenn ich jetzt auch ein Ablaufdatum für den Inhalt des Caches festlegen könnte, wäre mein Leben so viel einfacher 🙂
– Janusz
12. Juli 2011 um 7:11 Uhr
-
@Scienceprodigy keine Ahnung, was dieser BitmapLoader ist, ist sicherlich nicht in irgendeiner Standard-Android-Bibliothek, die ich kenne, aber es hat mich zumindest in die richtige Richtung geführt.
Bitmap response = BitmapFactory.decodeStream((InputStream)connection.getContent());
– Stefan Fuhry
30. September 2011 um 18:07 Uhr
-
Sehen Sie sich unbedingt Joes Antwort unten zu den zusätzlichen Schritten an, die Sie unternehmen müssen, damit der Cache funktioniert
– Keith
1. November 2011 um 18:22 Uhr
Jo
Apropos elegant connection.setUseCaches
Lösung oben: Ohne zusätzlichen Aufwand geht es leider nicht. Sie müssen eine installieren ResponseCache
verwenden ResponseCache.setDefault
. Andernfalls, HttpURLConnection
wird das stillschweigend ignorieren setUseCaches(true)
bisschen.
Siehe die Kommentare oben FileResponseCache.java
für Details:
(Ich würde dies in einem Kommentar posten, aber ich habe anscheinend nicht genug SO-Karma.)
-
-
Wenn Sie eine verwenden
HttpResponseCache
vielleicht finden Sie dieHttpResponseCache.getHitCount()
Rückgabe von 0. Ich bin mir nicht sicher, aber ich denke, das liegt daran, dass der von Ihnen angeforderte Webserver in diesem Fall keine Caching-Header verwendet. Damit das Caching trotzdem funktioniert, verwenden Sieconnection.addRequestProperty("Cache-Control", "max-stale=" + MAX_STALE_CACHE);
.– Almer
18. März 2013 um 14:51 Uhr
-
Der Link zur Google-Codesuche ist (wieder?) tot, bitte aktualisieren Sie den Link.
– Felix D.
8. Dezember 2016 um 15:26 Uhr
-
Ich bin mir auch nicht sicher, ob dieses Verhalten jetzt behoben ist. Aus irgendeinem Grund würde die Rückgabe von 304 vom Server HUC bei der Verwendung aufhängen
.getContent()
-Methode, da 304-Antworten gemäß RFC-Standard keinen zugeordneten Antworttext haben.– TheRealChx101
16. Juli 2019 um 16:58 Uhr
Konvertieren Sie sie in Bitmaps und speichern Sie sie dann entweder in einer Sammlung (HashMap, Liste usw.) oder schreiben Sie sie auf die SD-Karte.
Wenn Sie sie mit dem ersten Ansatz im Anwendungsbereich speichern, möchten Sie sie möglicherweise um a wickeln java.lang.ref.SoftReference insbesondere wenn ihre Anzahl groß ist (damit sie während der Krise von Müll abgeholt werden). Dies könnte jedoch ein Reload zur Folge haben.
HashMap<String,SoftReference<Bitmap>> imageCache =
new HashMap<String,SoftReference<Bitmap>>();
das Schreiben auf die SD-Karte erfordert kein Neuladen; nur eine Benutzerberechtigung.
-
Wie können wir ein Bild auf die SD-Karte oder den Telefonspeicher schreiben?
– D-Mann
22. Dezember 2009 um 11:05 Uhr
-
So speichern Sie Bilder auf einer SD-Karte: Sie können entweder die vom Remote-Server gelesenen Bildströme mit normalen Datei-E/A-Vorgängen in den Speicher schreiben oder, wenn Sie Ihre Bilder in Bitmap-Objekte konvertiert haben, die Methode Bitmap.compress() verwenden.
– Samuh
22. Dezember 2009 um 11:39 Uhr
-
@d-man Ich würde vorschlagen, zuerst die auf die Festplatte zu schreiben und dann eine zu erhalten
Uri
Pfadreferenz, an die Sie übergeben könnenImageView
und andere benutzerdefinierte Ansichten. Denn jedes Mal, wenn Siecompress
, du verlierst Qualität. Dies gilt natürlich nur für verlustbehaftete Algorithmen. Diese Methode würde es Ihnen auch ermöglichen, sogar einen Hash der Datei zu speichern und ihn zu verwenden, wenn Sie die Datei das nächste Mal vom Server anfordernIf-None-Match
undETag
Kopfzeilen.– TheRealChx101
16. Juli 2019 um 17:03 Uhr
-
@ TheRealChx101 könnten Sie bitte helfen zu verstehen, was Sie meinen Wenn Sie die Datei das nächste Mal vom Server über If-None-Match- und ETag-Header anfordernIch suche im Grunde nach einem Lösungsansatz, bei dem das Bild bleiben sollte, um den lokalen Cache für einen definierten Zeitraum zu verwenden, ODER wenn dies nicht erreicht werden kann, sollte es bei jeder Änderung des Inhalts für die URL in der Anwendung mit dem neuesten widergespiegelt und zwischengespeichert werden.
– Code
24. August 2019 um 1:06 Uhr
-
@CoDe Besuchen Sie jetzt diesen Link, android.jlelse.eu/…
– TheRealChx101
24. August 2019 um 22:19 Uhr
Zubair Ahmed
Verwenden LruCache
um Bilder effizient zwischenzuspeichern. Sie können darüber lesen LruCache
von Android-Entwicklerseite
Ich habe die folgende Lösung zum Herunterladen und Zwischenspeichern von Bildern in Android verwendet. Sie können die folgenden Schritte ausführen:
SCHRITT 1:
Klasse benannt machen ImagesCache
. Ich habe verwendet 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();
}
}
}
SCHRITT 2:
Erstellen Sie eine andere Klasse namens DownloadImageTask, die verwendet wird, wenn Bitmap nicht im Cache verfügbar ist, und sie von hier heruntergeladen wird:
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: Nutzung von Ihrem Activity
oder Adapter
Notiz: Wenn Sie ein Bild von einer URL laden möchten Activity
Klasse. Verwenden Sie den zweiten Konstruktor von DownloadImageTask
aber wenn Sie ein Bild von anzeigen möchten Adapter
Verwenden Sie den ersten Konstruktor von DownloadImageTask
(Beispiel: Sie haben ein Bild in ListView
und Sie stellen das Bild von ‘Adapter’ ein)
NUTZUNG VON AKTIVITÄTEN:
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);
}
Notiz:
cache.initializeCache()
Sie können diese Anweisung in der allerersten Aktivität Ihrer Bewerbung verwenden. Sobald Sie den Cache initialisiert haben, müssen Sie ihn nicht jedes Mal initialisieren, wenn Sie ihn verwenden ImagesCache
Beispiel.
Ich bin nie gut darin, Dinge zu erklären, aber ich hoffe, dass dies den Anfängern hilft, wie man cachet LruCache
und seine Verwendung 🙂
BEARBEITEN:
Heutzutage gibt es sehr berühmte Bibliotheken, die als bekannt sind Picasso
und Glide
die verwendet werden können, um Bilder sehr effizient in die Android-App zu laden. Probieren Sie diese sehr einfache und nützliche Bibliothek aus 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 – oft in einer Codezeile!
Glide kann, genau wie Picasso, Bilder aus vielen Quellen laden und anzeigen, während es sich auch um das Caching kümmert und eine geringe Speicherauslastung bei Bildmanipulationen beibehält. 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 für besuchen Unterschied zwischen Glide und Picasso
Um ein Bild herunterzuladen und auf der Speicherkarte zu speichern, können Sie wie folgt vorgehen.
//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" />
-
Warum dekodieren Sie das JPEG und kodieren es dann neu? Es ist besser, die URL in ein Byte-Array herunterzuladen und dann dieses Byte-Array zu verwenden, um Ihre Bitmap zu erstellen und in eine Datei zu schreiben. Jedes Mal, wenn Sie ein JPEG dekodieren und neu kodieren, verschlechtert sich die Bildqualität.
– CommonsWare
22. Dezember 2009 um 16:33 Uhr
-
Fairer Punkt, war mehr für Geschwindigkeit als alles andere. Obwohl, wenn als Byte-Array gespeichert und die Quelldatei kein JPEG wäre, müsste die Datei nicht trotzdem konvertiert werden? “decodeByteArray” aus dem SDK gibt “Die dekodierte Bitmap oder null zurück, wenn die Bilddaten nicht dekodiert werden konnten”, also denke ich, dass die Bilddaten immer dekodiert werden, also müsste dies nicht erneut kodiert werden?
– Ljdawson
22. Dezember 2009 um 17:32 Uhr
-
Apropos Effizienz, wäre es nicht effizient, wenn wir statt FileOutputStream BufferedOutputStream übergeben würden?
– Samuh
23. Dezember 2009 um 4:18 Uhr
-
Ich schlage nicht vor, Bilder auf Ihrer SD-Karte zwischenzuspeichern. Sobald die Anwendung deinstalliert ist, werden die Bilder nicht entfernt, wodurch die SD-Karte mit nutzlosem Müll gefüllt wird. Das Speichern von Bildern im Cache-Verzeichnis der Anwendung wird IMO bevorzugt
– James
28. Januar 2011 um 20:52 Uhr
-
Mit einem APK-Limit von jetzt 50 MB ist das Caching auf der SD-Karte möglicherweise die einzige Möglichkeit für Entwickler.
– Ljdawson
28. Januar 2011 um 21:24 Uhr
Kunu
Ich würde in Betracht ziehen, den Bildcache von droidfu zu verwenden. Es implementiert sowohl einen In-Memory- als auch einen festplattenbasierten Image-Cache. Sie erhalten auch eine WebImageView, die die Vorteile der 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/
-
Warum dekodieren Sie das JPEG und kodieren es dann neu? Es ist besser, die URL in ein Byte-Array herunterzuladen und dann dieses Byte-Array zu verwenden, um Ihre Bitmap zu erstellen und in eine Datei zu schreiben. Jedes Mal, wenn Sie ein JPEG dekodieren und neu kodieren, verschlechtert sich die Bildqualität.
– CommonsWare
22. Dezember 2009 um 16:33 Uhr
-
Fairer Punkt, war mehr für Geschwindigkeit als alles andere. Obwohl, wenn als Byte-Array gespeichert und die Quelldatei kein JPEG wäre, müsste die Datei nicht trotzdem konvertiert werden? “decodeByteArray” aus dem SDK gibt “Die dekodierte Bitmap oder null zurück, wenn die Bilddaten nicht dekodiert werden konnten”, also denke ich, dass die Bilddaten immer dekodiert werden, also müsste dies nicht erneut kodiert werden?
– Ljdawson
22. Dezember 2009 um 17:32 Uhr
-
Apropos Effizienz, wäre es nicht effizient, wenn wir statt FileOutputStream BufferedOutputStream übergeben würden?
– Samuh
23. Dezember 2009 um 4:18 Uhr
-
Ich schlage nicht vor, Bilder auf Ihrer SD-Karte zwischenzuspeichern. Sobald die Anwendung deinstalliert ist, werden die Bilder nicht entfernt, wodurch die SD-Karte mit nutzlosem Müll gefüllt wird. Das Speichern von Bildern im Cache-Verzeichnis der Anwendung wird IMO bevorzugt
– James
28. Januar 2011 um 20:52 Uhr
-
Mit einem APK-Limit von jetzt 50 MB ist das Caching auf der SD-Karte möglicherweise die einzige Möglichkeit für Entwickler.
– Ljdawson
28. Januar 2011 um 21:24 Uhr
2 TassenTech
Ich habe SoftReferences ausprobiert, sie werden in Android zu aggressiv zurückgefordert, dass ich der Meinung war, dass es keinen Sinn macht, sie zu verwenden
-
Einverstanden – SoftReferences werden auf den von mir getesteten Geräten sehr schnell zurückgefordert
– essilber
29. November 2011 um 7:04 Uhr
-
Google hat selbst bestätigt, dass Dalviks GC beim Sammeln sehr aggressiv ist
SoftReference
S. Sie empfehlen die Verwendung ihrerLruCache
stattdessen.– kaka
4. September 2012 um 21:08 Uhr