Как я могу кэшировать изображения после их загрузки из Интернета?
142
А теперь изюминка: используйте системный кеш.
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
usingResponseCache.setDefault
. В противном случае битHttpURLConnection
молча игнорируетсяsetUseCaches(true)
.Подробнее см. Комментарии вверху
FileResponseCache.java
:http://libs-for-android.googlecode.com/svn/reference/com/google/android/filecache/FileResponseCache.html
(Я бы разместил это в комментарии, но мне явно не хватает ТАКОЙ кармы.)
источник
HttpResponseCache
, вы можете обнаружить, чтоHttpResponseCache.getHitCount()
возвращается 0. Я не уверен, но я думаю, что это потому, что запрашиваемый вами веб-сервер в этом случае не использует кэширующие заголовки. Чтобы кеширование все равно работало, используйтеconnection.addRequestProperty("Cache-Control", "max-stale=" + MAX_STALE_CACHE);
..getContent()
метода, потому что ответы 304 не имеют связанного тела ответа по стандарту RFC.Преобразуйте их в растровые изображения, а затем либо сохраните их в коллекции (HashMap, List и т. Д.), Либо вы можете записать их на SD-карту.
При сохранении их в пространстве приложения с использованием первого подхода вы можете захотеть обернуть их вокруг java.lang.ref.SoftReference, особенно если их количество велико (чтобы они были собраны мусором во время кризиса). Однако это может привести к перезагрузке.
HashMap<String,SoftReference<Bitmap>> imageCache = new HashMap<String,SoftReference<Bitmap>>();
запись их на SD-карту не требует перезагрузки; просто разрешение пользователя.
источник
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
Class. Используйте второй конструктор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); }
ИСПОЛЬЗОВАНИЕ ОТ АДАПТЕРА:
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()
вы можете использовать этот оператор в самом первом Activity вашего приложения. После того, как вы инициализировали кеш, вам никогда не нужно будет инициализировать его каждый раз, если вы используетеImagesCache
instance.Я никогда не умею объяснять, но надеюсь, что это поможет новичкам понять, как использовать кеш
LruCache
и его использование :)РЕДАКТИРОВАТЬ:
Теперь есть очень известные библиотеки, известные как
Picasso
и,Glide
которые можно использовать для очень эффективной загрузки изображений в приложении для Android. Попробуйте эту очень простую и полезную библиотеку Picasso для Android и Glide для Android . Вам не нужно беспокоиться об изображениях в кеше.Вы также можете посетить блог, чтобы узнать о различиях между 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, они слишком агрессивно используются в Android, и я чувствовал, что их нет смысла использовать
источник
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, его
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 были хорошей альтернативой, но уже не, цитируя официальную страницу:
источник
Рассмотрите возможность использования универсальной библиотеки 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 имеет хорошие библиотеки для управления кешем изображений и файлов.
http://code.google.com/p/libs-for-android/
источник
Некоторое время я боролся с этим; ответы, использующие SoftReferences, будут терять свои данные слишком быстро. Ответы, предлагающие создать экземпляр RequestCache, были слишком беспорядочными, к тому же я так и не смог найти полный пример.
Но ImageDownloader.java у меня прекрасно работает. Он использует HashMap до тех пор, пока не будет достигнута емкость или пока не истечет время ожидания очистки, затем все будет перемещено в SoftReference, тем самым используя лучшее из обоих миров.
источник
Предлагаю IGNITION это даже лучше, чем Droid fu
https://github.com/kaeppler/ignition
https://github.com/kaeppler/ignition/wiki/Sample-applications
источник
Еще более поздний ответ, но я написал Android Image Manager, который прозрачно обрабатывает кеширование (память и диск). Код находится на Github https://github.com/felipecsl/Android-ImageManager
источник
Поздний ответ, но я полагал , что я должен добавить ссылку на мой сайт , потому что я написал учебник , как сделать тайник изображения для андроид:
http://squarewolf.nl/2010/11/android-image-cache/обновления: страница была переведена в офлайн, так как источник был устаревшим. Я присоединяюсь к @elenasys в ее совете по использованию Ignition .Итак, всем, кто сталкивается с этим вопросом и не нашел решения: надеюсь, вам понравится! = 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
источник