Risposte:
E ora la battuta finale: usa la cache di sistema.
URL url = new URL(strUrl);
URLConnection connection = url.openConnection();
connection.setUseCaches(true);
Object response = connection.getContent();
if (response instanceof Bitmap) {
Bitmap bitmap = (Bitmap)response;
}
Fornisce memoria e cache flash-rom, condivise con il browser.
GRR. Vorrei che qualcuno me lo avesse detto prima di scrivere il mio gestore di cache.
connection.getContent()
restituisce sempre un InputStream per me, cosa sto facendo di sbagliato?
Bitmap response = BitmapFactory.decodeStream((InputStream)connection.getContent());
Per quanto riguarda l'elegante connection.setUseCaches
soluzione sopra: purtroppo, non funzionerà senza alcuno sforzo aggiuntivo. Dovrai installare un ResponseCache
utilizzo ResponseCache.setDefault
. Altrimenti, HttpURLConnection
ignorerà silenziosamente il setUseCaches(true)
bit.
Vedere i commenti nella parte superiore di FileResponseCache.java
per i dettagli:
(Pubblicherei questo in un commento, ma a quanto pare non ho abbastanza karma SO.)
HttpResponseCache
, potresti trovare lo HttpResponseCache.getHitCount()
0. di ritorno non sono sicuro, ma penso che sia perché il server web che stai richiedendo non usa le intestazioni di cache in quel caso. Per far funzionare comunque la memorizzazione nella cache, utilizzare connection.addRequestProperty("Cache-Control", "max-stale=" + MAX_STALE_CACHE);
.
.getContent()
metodo perché 304 risposte non hanno un corpo di risposta associato secondo lo standard RFC.
Convertili in bitmap e poi memorizzali in una raccolta (HashMap, elenco ecc.) Oppure puoi scriverli sulla scheda SD.
Quando li memorizzi nello spazio dell'applicazione usando il primo approccio, potresti volerli avvolgere attorno a java.lang.ref.SoftReference in particolare se il loro numero è grande (in modo che siano spazzatura raccolti durante la crisi). Ciò potrebbe tuttavia comportare un Ricarico.
HashMap<String,SoftReference<Bitmap>> imageCache =
new HashMap<String,SoftReference<Bitmap>>();
scriverli su SDcard non richiederà un Ricarica; solo un permesso dell'utente.
Uri
riferimento al percorso che puoi passare ImageView
e altre viste personalizzate. Perché ogni volta compress
perderai qualità. Naturalmente questo è vero solo per gli algoritmi con perdita. Questo metodo ti consentirebbe anche di archiviare un hash del file e utilizzarlo la prossima volta che richiedi il file dal server attraverso If-None-Match
e le ETag
intestazioni.
Utilizzare LruCache
per memorizzare le immagini in modo efficiente. Puoi leggere informazioni LruCache
dal sito per sviluppatori Android
Ho usato la soluzione di seguito per il download di immagini e la memorizzazione nella cache in Android. Puoi seguire i passaggi seguenti:
PASSAGGIO 1:
crea un nome di classe ImagesCache
. Ho usatoSingleton 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();
}
}
}
PASSO 2:
crea un'altra classe denominata DownloadImageTask che viene utilizzata se bitmap non è disponibile nella cache e la scaricherà da qui:
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;
}
PASSAGGIO 3: utilizzo da Activity
oAdapter
Nota: se si desidera caricare l'immagine dall'URL dalla Activity
classe. Utilizzare il secondo costruttore di DownloadImageTask
, ma se si desidera visualizzare l'immagine Adapter
dall'uso primo costruttore di DownloadImageTask
(ad esempio, si dispone di un'immagine ListView
e si sta impostando l'immagine da 'Adattatore')
UTILIZZO DA ATTIVITÀ:
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);
}
USO DALL'ADATTATORE:
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);
}
Nota:
cache.initializeCache()
è possibile utilizzare questa affermazione nella prima attività dell'applicazione. Dopo aver inizializzato la cache, non sarà più necessario inizializzarla ogni volta che si utilizzaImagesCache
istanza.
Non sono mai bravo a spiegare le cose, ma spero che questo aiuterà i principianti a usare la cache LruCache
e il suo utilizzo :)
MODIFICARE:
Ora un giorno ci sono librerie molto famose conosciute come Picasso
e Glide
che possono essere utilizzate per caricare immagini in modo molto efficiente nell'app per Android. Prova questa libreria Picasso per Android molto semplice e utile e Glide per Android . Non devi preoccuparti delle immagini cache.
Picasso consente il caricamento delle immagini senza problemi nella tua applicazione, spesso in una riga di codice!
Glide, proprio come Picasso, può caricare e visualizzare immagini da molte fonti, occupandosi anche della memorizzazione nella cache e mantenendo un basso impatto di memoria durante le manipolazioni delle immagini. È stato utilizzato da app Google ufficiali (come l'app per Google I / O 2015) ed è altrettanto popolare come Picasso. In questa serie, esploreremo le differenze e i vantaggi di Glide su Picasso.
Puoi anche visitare il blog per la differenza tra Glide e Picasso
if(cache == null)
che ha risolto il mio problema! :)
Per scaricare un'immagine e salvarla sulla memory card puoi farlo in questo modo.
//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));
Non dimenticare di aggiungere l'autorizzazione Internet al tuo manifest:
<uses-permission android:name="android.permission.INTERNET" />
Vorrei prendere in considerazione l'utilizzo della cache delle immagini di Droidfu. Implementa una cache di immagini sia in memoria che su disco. Ottieni anche un WebImageView che sfrutta la libreria ImageCache.
Ecco la descrizione completa di droidfu e WebImageView: http://brainflush.wordpress.com/2009/11/23/droid-fu-part-2-webimageview-and-webgalleryadapter/
Ho provato SoftReferences, sono stati recuperati in modo troppo aggressivo in Android da non aver senso usarli
SoftReference
elettronica. Raccomandano LruCache
invece di usare il loro .
Come suggerito da Thunder Rabbit, ImageDownloader è il migliore per il lavoro. Ho anche trovato una leggera variazione della classe su:
http://theandroidcoder.com/utilities/android-image-download-and-caching/
La differenza principale tra i due è che ImageDownloader utilizza il sistema di memorizzazione nella cache Android e quello modificato utilizza la memorizzazione interna ed esterna come memorizzazione nella cache, mantenendo le immagini memorizzate nella cache indefinitamente o fino a quando l'utente non le rimuove manualmente. L'autore menziona anche la compatibilità con Android 2.1.
Questa è una buona cattura di Joe. L'esempio di codice sopra riportato ha due problemi: uno: l'oggetto response non è un'istanza di Bitmap (quando il mio URL fa riferimento a un jpg, come http: \ website.com \ image.jpg, è un
org.apache.harmony.luni.internal.net.www.protocol.http.HttpURLConnectionImpl $ LimitedInputStream).
In secondo luogo, come sottolinea Joe, non si verifica alcuna memorizzazione nella cache senza la configurazione di una cache di risposta. Gli sviluppatori Android possono lasciare la propria cache. Ecco un esempio per farlo, ma memorizza solo nella memoria cache, che in realtà non è la soluzione completa.
http://codebycoffee.com/2010/06/29/using-responsecache-in-an-android-app/
L'API di memorizzazione nella cache URLConnection è descritta qui:
http://download.oracle.com/javase/6/docs/technotes/guides/net/http-cache.html
Penso ancora che questa sia una soluzione OK per seguire questa strada, ma devi ancora scrivere una cache. Sembra divertente, ma preferirei scrivere funzionalità.
C'è una voce speciale sulla sezione di allenamento ufficiale di Android su questo: http://developer.android.com/training/displaying-bitmaps/cache-bitmap.html
La sezione è abbastanza nuova, non era presente quando è stata posta la domanda.
La soluzione suggerita è utilizzare un LruCache. Quella classe è stata introdotta su Honeycomb, ma è anche inclusa nella libreria di compatibilità.
È possibile inizializzare un LruCache impostando il numero massimo o le voci e li ordinerà automaticamente e li pulirà quelli meno usati quando si supera il limite. Diverso da quello che viene utilizzato come una normale mappa.
Il codice di esempio dalla pagina ufficiale:
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);
}
Precedentemente SoftReferences era una buona alternativa, ma non più, citando dalla pagina ufficiale:
Nota: in passato un'implementazione della cache di memoria popolare era una cache bitmap SoftReference o WeakReference, tuttavia non è consigliabile. A partire da Android 2.3 (Livello API 9), il garbage collector è più aggressivo con la raccolta di riferimenti deboli / deboli che li rende abbastanza inefficaci. Inoltre, prima di Android 3.0 (API Level 11), i dati di backup di una bitmap erano archiviati nella memoria nativa che non è stata rilasciata in modo prevedibile, causando potenzialmente il superamento di un limite di memoria e l'arresto anomalo di un'applicazione.
Prendi in considerazione l'utilizzo della libreria Universal Image Loader di Sergey Tarasevich . Viene fornito con:
Universal Image Loader consente la gestione dettagliata della cache per le immagini scaricate, con le seguenti configurazioni di cache:
UsingFreqLimitedMemoryCache
: La bitmap utilizzata meno frequentemente viene eliminata quando viene superato il limite della dimensione della cache.LRULimitedMemoryCache
: La bitmap utilizzata meno di recente viene eliminata quando viene superato il limite della dimensione della cache.FIFOLimitedMemoryCache
: La regola FIFO viene utilizzata per l'eliminazione quando viene superato il limite della dimensione della cache.LargestLimitedMemoryCache
: La bitmap più grande viene eliminata quando viene superato il limite della dimensione della cache.LimitedAgeMemoryCache
: L'oggetto memorizzato nella cache viene eliminato quando la sua età supera il valore definito .WeakMemoryCache
: Una cache di memoria con solo riferimenti deboli a bitmap.Un semplice esempio di utilizzo:
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 questo esempio viene utilizzato il valore predefinito UsingFreqLimitedMemoryCache
.
Ciò che effettivamente ha funzionato per me è stato impostare ResponseCache sulla mia classe Main:
try {
File httpCacheDir = new File(getApplicationContext().getCacheDir(), "http");
long httpCacheSize = 10 * 1024 * 1024; // 10 MiB
HttpResponseCache.install(httpCacheDir, httpCacheSize);
} catch (IOException e) { }
e
connection.setUseCaches(true);
durante il download di bitmap.
http://practicaldroid.blogspot.com/2013/01/utilizing-http-response-cache.html
Libs-for-android di Google ha delle belle librerie per la gestione della cache di immagini e file.
Ho lottato con questo per qualche tempo; le risposte usando SoftReferences perderebbero i loro dati troppo rapidamente. Le risposte che suggeriscono di creare un'istanza di RequestCache erano troppo complicate, inoltre non sono mai riuscito a trovare un esempio completo.
Ma ImageDownloader.java funziona meravigliosamente per me. Utilizza una HashMap fino a quando non viene raggiunta la capacità o finché non si verifica il timeout di spurgo, quindi le cose vengono spostate su un SoftReference, utilizzando quindi il meglio dei due mondi.
Suggerisco IGNITION che è persino meglio di Droid fu
https://github.com/kaeppler/ignition
https://github.com/kaeppler/ignition/wiki/Sample-applications
Anche dopo la risposta, ma ho scritto un gestore di immagini Android che gestisce la cache in modo trasparente (memoria e disco). Il codice è su Github https://github.com/felipecsl/Android-ImageManager
Risposta in ritardo, ma ho pensato di aggiungere un link al mio sito perché ho scritto un tutorial su come creare una cache di immagini per Android: http://squarewolf.nl/2010/11/android-image-cache/ Update: the la pagina è stata messa offline come la fonte non era aggiornata. Mi unisco a @elenasys nel suo consiglio di usare Ignition .
Quindi a tutte le persone che si imbattono in questa domanda e non hanno trovato una soluzione: spero vi piaccia! = D
Risposta in ritardo, ma penso che questa libreria aiuterà molto con la memorizzazione delle immagini nella cache: https://github.com/crypticminds/ColdStorage .
Annota semplicemente ImageView con @LoadCache (R.id.id_of_my_image_view, "URL_to_downlaod_image_from) e si occuperà di scaricare l'immagine e caricarla nella vista immagine. Puoi anche specificare un'immagine segnaposto e caricare l'animazione.
La documentazione dettagliata dell'annotazione è presente qui: - https://github.com/crypticminds/ColdStorage/wiki/@LoadImage-annotation