Відповіді:
А тепер пуншлін: використовуйте системний кеш.
URL url = new URL(strUrl);
URLConnection connection = url.openConnection();
connection.setUseCaches(true);
Object response = connection.getContent();
if (response instanceof Bitmap) {
Bitmap bitmap = (Bitmap)response;
}
Забезпечує кеш пам’яті та флеш-пам’яті кеш-пам’яті, що ділиться з браузером
грр. Я хотів би, щоб хтось сказав мені, що перед тим, як я написав власний кеш-менеджер.
connection.getContent()
завжди повертає InputStream для мене, що я роблю неправильно?
Bitmap response = BitmapFactory.decodeStream((InputStream)connection.getContent());
Щодо елегантного connection.setUseCaches
рішення вище: на жаль, воно не спрацює без додаткових зусиль. Вам потрібно буде встановити ResponseCache
користування ResponseCache.setDefault
. Інакше HttpURLConnection
буде мовчки ігнорувати setUseCaches(true)
шматочок.
FileResponseCache.java
Деталі див. У коментарях вгорі :
(Я опублікував це в коментарі, але мені, мабуть, не вистачає ТАК карми.)
HttpResponseCache
, ви можете знайти HttpResponseCache.getHitCount()
повертається 0. Я не впевнений, але я думаю, що це тому, що веб-сервер, про який ви запитуєте, не використовує заголовки кешування в цьому випадку. Щоб кеш-роботу все-таки працювало, використовуйте connection.addRequestProperty("Cache-Control", "max-stale=" + MAX_STALE_CACHE);
.
.getContent()
методу, оскільки 304 відповіді не мають асоційованого органу відповідей за стандартом RFC.
Перетворіть їх у бітові карти, а потім збережіть їх у колекції (HashMap, список тощо) або можете записати їх на SDcard.
Зберігаючи їх у прикладному просторі за допомогою першого підходу, ви можете обернути їх навколо java.lang.ref.SoftReference, зокрема, якщо їх кількість велика (щоб вони зібрали сміття під час кризи). Це може спричинити перезавантаження.
HashMap<String,SoftReference<Bitmap>> imageCache =
new HashMap<String,SoftReference<Bitmap>>();
запис їх на SDcard не потребує перезавантаження; просто дозвіл користувача.
Uri
посилання на шлях, який ви можете перейти ImageView
та інші власні представлення даних. Тому що кожного разу compress
, коли ти будеш, ти будеш втрачати якість. Звичайно, це стосується лише алгоритмів втрат. Цей метод також дозволить вам навіть зберігати хеш файлу та використовувати його наступного разу, коли ви запитаєте файл із сервера через If-None-Match
та ETag
заголовки.
Використовуйте LruCache
для ефективного кешування зображень. Про це можна прочитати LruCache
з сайту розробника Android
Нижче я використовував рішення для завантаження зображень та кешування в 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
Примітка. Якщо ви хочете завантажити зображення з URL-адреси з Activity
класу. Використовуйте другий конструктор 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);
}
ВИКОРИСТАННЯ ВІД 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);
}
Примітка:
cache.initializeCache()
Ви можете використовувати цю заяву в першій діяльності Вашої програми. Після ініціалізації кеша вам ніколи не доведеться ініціалізувати його кожен раз, якщо ви використовуєте ImagesCache
екземпляр.
Я ніколи не вмію пояснювати речі, але сподіваюся, що це допоможе новачкам у тому, як кешувати LruCache
та використовувати його :)
Редагувати:
Зараз уже кілька днів є дуже відомі бібліотеки, відомі як Picasso
і Glide
які можна використовувати для ефективної завантаження зображень в додатку для Android. Спробуйте цю дуже просту і корисну бібліотеку Picasso для android та Glide For Android . Не потрібно турбуватися про зображення кешу.
Picasso дозволяє без проблем завантажувати зображення у вашій програмі - часто в одному рядку коду!
Glide, як і Пікассо, може завантажувати та показувати зображення з багатьох джерел, а також дбаючи про кешування та зберігаючи низький вплив на пам'ять під час маніпуляцій із зображеннями. Він використовувався офіційними програмами Google (наприклад, програма Google I / O 2015) і настільки ж популярний, як і Пікассо. У цій серії ми будемо досліджувати відмінності та переваги ковзання над Пікассо.
Ви також можете відвідати блог щодо різниці між Glide та Picasso
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. Він реалізує як кеш-пам'ять зображення, так і пам'ять на основі диска. Ви також отримуєте WebImageView, який використовує перевагу бібліотеки ImageCache.
Ось повний опис droidfu та WebImageView: http://brainflush.wordpress.com/2009/11/23/droid-fu-part-2-webimageview-and-webgalleryadapter/
Я спробував SoftReferences, вони занадто агресивно повертаються в андроїд, щоб я відчував, що їх немає сенсу використовувати
SoftReference
s. Вони рекомендують використовувати LruCache
замість них.
Як запропонував Thunder Rabbit, ImageDownloader є найкращим для роботи. Я також виявив незначну зміну класу у:
http://theandroidcoder.com/utilities/android-image-download-and-caching/
Основна відмінність між ними полягає в тому, що ImageDownloader використовує систему кешування Android, а модифікована використовує внутрішнє та зовнішнє сховище як кешування, зберігаючи кешовані зображення на невизначений термін або поки користувач не видалить їх вручну. Автор також згадує сумісність Android 2.1.
Це хороший улов Джо. У наведеному вище прикладі коду є дві проблеми - одна - об'єкт відповіді не є примірником Bitmap (коли моя URL-адреса посилається на jpg, як-от http: \ website.com \ image.jpg, його a
org.apache.harmony.luni.internal.net.www.protocol.http.HttpURLConnectionImpl $ LimitedInputStream).
По-друге, як вказує Джо, жодне кешування не відбувається без налаштування кешу відповідей. Розробникам Android залишається керувати власним кешем. Ось приклад для цього, але це зберігається лише в пам'яті, що насправді не є повним рішенням.
http://codebycoffee.com/2010/06/29/using-responsecache-in-an-android-app/
Тут описаний API кешування URLConnection:
http://download.oracle.com/javase/6/docs/technotes/guides/net/http-cache.html
Я все ще думаю, що це нормальне рішення, щоб пройти цей маршрут - але ви все одно повинні написати кеш. Здається, це весело, але я краще пишу функції.
У офіційному навчальному розділі Android про це є спеціальний запис: http://developer.android.com/training/displaying-bitmaps/cache-bitmap.html
Розділ досить новий, його там не було, коли було задано питання.
Пропоноване рішення - використовувати LruCache. Цей клас був представлений на Honeycomb, але він також включений до бібліотеки сумісності.
Ви можете ініціалізувати 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) резервні дані растрової карти зберігалися у рідній пам’яті, яка не вивільняється передбачуваним чином, що потенційно може призвести до того, що програма ненадовго перевищить межі своєї пам’яті та вийде з ладу.
Подумайте про використання бібліотеки 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, використовуючи тим самим найкращі з обох світів.
Я пропоную ВПАДЕННЯ, це навіть краще, ніж Droid fu
https://github.com/kaeppler/ignition
https://github.com/kaeppler/ignition/wiki/Sample-applications
Ще пізніше відповідаю, але я написав диспетчер зображень Android, який керує кешами прозоро (пам'ять та диск). Код знаходиться на Github https://github.com/felipecsl/Android-ImageManager
Пізня відповідь, але я подумав, що я повинен додати посилання на свій сайт, тому що я написав підручник, як зробити кеш зображень для андроїда: http://squarewolf.nl/2010/11/android-image-cache/ Оновлення: the Сторінку було знято в автономному режимі, оскільки джерело застаріло. Я приєднуюся до @elenasys в її пораді щодо використання запалювання .
Тож усім людям, які натрапляють на це питання і не знайшли рішення: сподіваюся, вам сподобається! = D
Пізня відповідь, але я думаю, що ця бібліотека дуже допоможе при кешуванні зображень: https://github.com/crypticminds/ColdStorage .
Просто анотуйте ImageView за допомогою @LoadCache (R.id.id_of_my_image_view, "URL_to_downlaod_image_from), і він подбає про завантаження зображення та завантаження його у перегляд зображення. Ви також можете вказати зображення заповнювача та анімацію завантаження.
Детальна документація анотації представлена тут: - https://github.com/crypticminds/ColdStorage/wiki/@LoadImage-annotation