Réponses:
Et maintenant la punchline: utilisez le cache système.
URL url = new URL(strUrl);
URLConnection connection = url.openConnection();
connection.setUseCaches(true);
Object response = connection.getContent();
if (response instanceof Bitmap) {
Bitmap bitmap = (Bitmap)response;
}
Fournit à la fois de la mémoire et un cache flash-rom, partagés avec le navigateur.
grr. J'aurais aimé que quelqu'un ME dise cela avant d'écrire mon propre gestionnaire de cache.
connection.getContent()
renvoie toujours un InputStream pour moi, qu'est-ce que je fais de mal?
Bitmap response = BitmapFactory.decodeStream((InputStream)connection.getContent());
En ce qui concerne la connection.setUseCaches
solution élégante ci-dessus: malheureusement, cela ne fonctionnera pas sans un effort supplémentaire. Vous devrez installer un fichier ResponseCache
using ResponseCache.setDefault
. Sinon, HttpURLConnection
ignorera silencieusement le setUseCaches(true)
bit.
Voir les commentaires en haut de FileResponseCache.java
pour plus de détails:
(Je publierais ceci dans un commentaire, mais je n'ai apparemment pas assez de karma SO.)
HttpResponseCache
, vous pouvez trouver le HttpResponseCache.getHitCount()
retour 0. Je ne suis pas sûr mais je pense que c'est parce que le serveur Web que vous demandez n'utilise pas les en-têtes de mise en cache dans ce cas. Pour que la mise en cache fonctionne de toute façon, utilisez connection.addRequestProperty("Cache-Control", "max-stale=" + MAX_STALE_CACHE);
.
.getContent()
méthode car les réponses 304 n'ont pas de corps de réponse associé par la norme RFC.
Convertissez-les en bitmaps, puis stockez-les dans une collection (HashMap, liste, etc.) ou vous pouvez les écrire sur la carte SD.
Lorsque vous les stockez dans l'espace d'application en utilisant la première approche, vous voudrez peut-être les enrouler autour d'un java.lang.ref.SoftReference spécifiquement si leur nombre est grand (afin qu'ils soient ramassés pendant la crise). Cela pourrait cependant entraîner un rechargement.
HashMap<String,SoftReference<Bitmap>> imageCache =
new HashMap<String,SoftReference<Bitmap>>();
les écrire sur la carte SD ne nécessitera pas de rechargement; juste une permission d'utilisateur.
Uri
référence de chemin à laquelle vous pouvez passer ImageView
et d'autres vues personnalisées. Parce qu'à chaque fois compress
, vous perdrez de la qualité. Bien sûr, cela n'est vrai que pour les algorithmes avec perte. Cette méthode vous permettrait également de stocker même un hachage du fichier et de l'utiliser la prochaine fois que vous demanderez le fichier au serveur via If-None-Match
et les en- ETag
têtes.
Utilisez LruCache
pour mettre en cache les images efficacement. Vous pouvez lire à LruCache
partir de Android site développeur
J'ai utilisé la solution ci-dessous pour le téléchargement d'images et la mise en cache dans Android. Vous pouvez suivre les étapes ci-dessous:
ÉTAPE 1:
créez la classe nommée ImagesCache
. J'ai utilisé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();
}
}
}
ÉTAPE 2:
créez une autre classe nommée DownloadImageTask qui est utilisée si le bitmap n'est pas disponible dans le cache, il le téléchargera à partir d'ici:
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;
}
ÉTAPE 3: Utilisation depuis votre Activity
ouAdapter
Remarque: si vous souhaitez charger une image à partir de l'URL de Activity
Class. Utilisez le deuxième constructeur de DownloadImageTask
, mais si vous souhaitez afficher l'image à partir du Adapter
premier constructeur de DownloadImageTask
(par exemple, vous avez une image dans ListView
et vous définissez l'image à partir de 'Adapter')
UTILISATION DE L'ACTIVITÉ:
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);
}
UTILISATION DE L'ADAPTATEUR:
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);
}
Remarque:
cache.initializeCache()
vous pouvez utiliser cette instruction dans la toute première activité de votre application. Une fois que vous avez initialisé le cache, vous n'aurez jamais besoin de l'initialiser à chaque fois si vous utilisez ImagesCache
instance.
Je ne suis jamais doué pour expliquer les choses mais j'espère que cela aidera les débutants à savoir comment mettre en cache l'utilisation LruCache
et son utilisation :)
ÉDITER:
Aujourd'hui, il existe des bibliothèques très célèbres connues sous le nom de Picasso
et Glide
qui peuvent être utilisées pour charger des images très efficacement dans l'application Android. Essayez cette bibliothèque très simple et utile Picasso pour Android et Glide pour Android . Vous n'avez pas à vous soucier des images de cache.
Picasso permet un chargement d'image sans tracas dans votre application, souvent en une seule ligne de code!
Glide, tout comme Picasso, peut charger et afficher des images provenant de nombreuses sources, tout en prenant en charge la mise en cache et en conservant un faible impact sur la mémoire lors des manipulations d'images. Il a été utilisé par les applications officielles de Google (comme l'application pour Google I / O 2015) et est tout aussi populaire que Picasso. Dans cette série, nous allons explorer les différences et les avantages de Glide sur Picasso.
Vous pouvez également visiter le blog pour la différence entre Glide et Picasso
if(cache == null)
qui a résolu mon problème! :)
Pour télécharger une image et l'enregistrer sur la carte mémoire, vous pouvez le faire comme ceci.
//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));
N'oubliez pas d'ajouter l'autorisation Internet à votre manifeste:
<uses-permission android:name="android.permission.INTERNET" />
J'envisagerais d'utiliser le cache d'image de droidfu. Il implémente à la fois un cache d'image en mémoire et sur disque. Vous obtenez également un WebImageView qui tire parti de la bibliothèque ImageCache.
Voici la description complète de droidfu et WebImageView: http://brainflush.wordpress.com/2009/11/23/droid-fu-part-2-webimageview-and-webgalleryadapter/
J'ai essayé SoftReferences, ils sont récupérés de manière trop agressive dans Android que je sentais qu'il ne servait à rien de les utiliser
SoftReference
art. Ils recommandent d'utiliser leur à la LruCache
place.
Comme l'a suggéré Thunder Rabbit, ImageDownloader est le meilleur pour le travail. J'ai également trouvé une légère variation de la classe à:
http://theandroidcoder.com/utilities/android-image-download-and-caching/
La principale différence entre les deux est que ImageDownloader utilise le système de mise en cache Android et que celui modifié utilise le stockage interne et externe comme mise en cache, conservant les images en cache indéfiniment ou jusqu'à ce que l'utilisateur le supprime manuellement. L'auteur mentionne également la compatibilité Android 2.1.
C'est une bonne prise de Joe. L'exemple de code ci-dessus a deux problèmes - un - l'objet de réponse n'est pas une instance de Bitmap (lorsque mon URL fait référence à un jpg, comme http: \ website.com \ image.jpg, c'est un
org.apache.harmony.luni.internal.net.www.protocol.http.HttpURLConnectionImpl $ LimitedInputStream).
Deuxièmement, comme le souligne Joe, aucune mise en cache n'a lieu sans la configuration d'un cache de réponse. Les développeurs Android doivent rouler leur propre cache. Voici un exemple pour le faire, mais cela ne met en cache que la mémoire, ce qui n'est vraiment pas la solution complète.
http://codebycoffee.com/2010/06/29/using-responsecache-in-an-android-app/
L'API de mise en cache URLConnection est décrite ici:
http://download.oracle.com/javase/6/docs/technotes/guides/net/http-cache.html
Je pense toujours que c'est une bonne solution pour suivre cette voie - mais vous devez toujours écrire un cache. Cela semble amusant, mais je préfère écrire des fonctionnalités.
Il y a une entrée spéciale dans la section de formation officielle d'Android à ce sujet: http://developer.android.com/training/displaying-bitmaps/cache-bitmap.html
La section est assez récente, elle n'était pas là lorsque la question a été posée.
La solution suggérée est d'utiliser un LruCache. Cette classe a été introduite sur Honeycomb, mais elle est également incluse dans la bibliothèque de compatibilité.
Vous pouvez initialiser un LruCache en définissant le nombre maximum d'entrées et il les triera automatiquement à votre guise et les nettoiera les moins utilisées lorsque vous dépassez la limite. Autre que cela, il est utilisé comme une carte normale.
L'exemple de code de la page officielle:
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);
}
Auparavant, SoftReferences était une bonne alternative, mais plus maintenant, citant la page officielle:
Remarque: Dans le passé, une implémentation de cache mémoire populaire était un cache bitmap SoftReference ou WeakReference, mais cela n'est pas recommandé. À partir d'Android 2.3 (niveau d'API 9), le garbage collector est plus agressif avec la collecte de références souples / faibles, ce qui les rend assez inefficaces. De plus, avant Android 3.0 (niveau d'API 11), les données de sauvegarde d'un bitmap étaient stockées dans la mémoire native qui n'est pas libérée de manière prévisible, ce qui pourrait entraîner un dépassement bref de ses limites de mémoire et un crash d'une application.
Envisagez d'utiliser la bibliothèque Universal Image Loader de Sergey Tarasevich . Il est livré avec:
Universal Image Loader permet une gestion détaillée du cache pour les images téléchargées, avec les configurations de cache suivantes:
UsingFreqLimitedMemoryCache
: Le bitmap le moins fréquemment utilisé est supprimé lorsque la limite de taille du cache est dépassée.LRULimitedMemoryCache
: Le bitmap le moins récemment utilisé est supprimé lorsque la limite de taille du cache est dépassée.FIFOLimitedMemoryCache
: La règle FIFO est utilisée pour la suppression lorsque la limite de taille du cache est dépassée.LargestLimitedMemoryCache
: Le bitmap le plus grand est supprimé lorsque la limite de taille du cache est dépassée.LimitedAgeMemoryCache
: L'objet mis en cache est supprimé lorsque son âge dépasse la valeur définie .WeakMemoryCache
: Un cache mémoire avec uniquement des références faibles aux bitmaps.Un exemple d'utilisation simple:
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);
Cet exemple utilise la valeur par défaut UsingFreqLimitedMemoryCache
.
Ce qui a réellement fonctionné pour moi a été de définir ResponseCache sur ma classe Main:
try {
File httpCacheDir = new File(getApplicationContext().getCacheDir(), "http");
long httpCacheSize = 10 * 1024 * 1024; // 10 MiB
HttpResponseCache.install(httpCacheDir, httpCacheSize);
} catch (IOException e) { }
et
connection.setUseCaches(true);
lors du téléchargement de bitmap.
http://practicaldroid.blogspot.com/2013/01/utilizing-http-response-cache.html
Les libs-for-android de Google ont de belles bibliothèques pour gérer le cache d'images et de fichiers.
J'avais lutté avec ça depuis un certain temps; les réponses utilisant SoftReferences perdraient leurs données trop rapidement. Les réponses qui suggèrent d'instancier un RequestCache étaient trop compliquées et je n'ai jamais pu trouver d'exemple complet.
Mais ImageDownloader.java fonctionne à merveille pour moi. Il utilise un HashMap jusqu'à ce que la capacité soit atteinte ou jusqu'à ce que le délai de purge se produise, puis les choses sont déplacées vers une SoftReference, utilisant ainsi le meilleur des deux mondes.
Je suggère IGNITION c'est encore mieux que Droid fu
https://github.com/kaeppler/ignition
https://github.com/kaeppler/ignition/wiki/Sample-applications
Réponse encore plus tardive, mais j'ai écrit un gestionnaire d'images Android qui gère la mise en cache de manière transparente (mémoire et disque). Le code est sur Github https://github.com/felipecsl/Android-ImageManager
Réponse tardive, mais je me suis dit que je devrais ajouter un lien vers mon site car j'ai écrit un tutoriel sur la création d'un cache d'image pour Android: http://squarewolf.nl/2010/11/android-image-cache/ Mise à jour: le La page a été mise hors ligne car la source était obsolète. Je rejoins @elenasys dans ses conseils d'utilisation d' Ignition .
Alors à toutes les personnes qui tombent sur cette question et n'ont pas trouvé de solution: j'espère que vous apprécierez! = D
Réponse tardive mais je pense que cette bibliothèque aidera beaucoup avec la mise en cache des images: https://github.com/crypticminds/ColdStorage .
Annotez simplement l'ImageView avec @LoadCache (R.id.id_of_my_image_view, "URL_to_downlaod_image_from) et il se chargera de télécharger l'image et de la charger dans la vue d'image. Vous pouvez également spécifier une image d'espace réservé et charger l'animation.
Une documentation détaillée de l'annotation est présente ici: - https://github.com/crypticminds/ColdStorage/wiki/@LoadImage-annotation