Как я могу кэшировать изображения после их загрузки из Интернета?
Кэширование изображений в Интернете
Ответ 1
И теперь пуанлинг: используйте системный кеш.
URL url = new URL(strUrl);
URLConnection connection = url.openConnection();
connection.setUseCaches(true);
Object response = connection.getContent();
if (response instanceof Bitmap) {
  Bitmap bitmap = (Bitmap)response;
} 
Обеспечивает как кеш памяти, так и флэш-диск, совместно используемый браузером.
ГРР. Я хотел бы, чтобы кто-то сказал мне, что прежде чем я напишу свой собственный менеджер кэшей.
Ответ 2
Что касается элегантного решения connection.setUseCaches выше: к сожалению, он не будет работать без каких-либо дополнительных усилий. Вам нужно будет установить ResponseCache с помощью ResponseCache.setDefault. В противном случае HttpURLConnection будет молча игнорировать бит setUseCaches(true).
Подробнее см. комментарии в верхней части FileResponseCache.java:
(Я бы опубликовал это в комментарии, но, по-видимому, мне не хватает SO кармы.)
Ответ 3
Преобразуйте их в растровые изображения, а затем сохраните их в коллекции (HashMap, List и т.д.) или вы можете записать их на SD-карте.
При хранении их в пространстве приложения с использованием первого подхода вы можете обернуть их вокруг java.lang.ref.SoftReference, особенно если их номера большие (чтобы они были собраны во время кризиса). Это может привести к перезагрузке.
HashMap<String,SoftReference<Bitmap>> imageCache =
        new HashMap<String,SoftReference<Bitmap>>();
запись на SD-карту не потребует перезагрузки; просто разрешение пользователя.
Ответ 4
Используйте 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);
}
ИСПОЛЬЗОВАНИЕ ИЗ АДАПТЕРА:
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 и его использование :)
EDIT:
Сейчас существуют очень известные библиотеки, известные как Picasso и Glide, которые можно использовать для очень эффективной загрузки изображений в приложении для Android. Попробуйте эту очень простую и полезную библиотеку Picasso для Android и Glide For Android. Вам не нужно беспокоиться о кэше изображений.
Picasso позволяет без проблем загружать изображения в ваше приложение - часто в одной строке кода!
Glide, как и Picasso, может загружать и отображать изображения от многих источники, а также заботиться о кэшировании и сохранении памяти влияние при выполнении манипуляций с изображениями Он был использован официальным Приложения Google (например, приложение для Google I/O 2015) и столь же популярны как Пикассо. В этой серии мы рассмотрим различия и Преимущества Glide перед Пикассо.
Вы также можете посетить блог для разницы между Glide и Picasso
Ответ 5
Чтобы загрузить изображение и сохранить на карту памяти, вы можете сделать это следующим образом.
//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" />
Ответ 6
Я бы рассмотрел использование кэша изображений droidfu. Он реализует как кеш-память в памяти, так и диск. Вы также получаете WebImageView, который использует библиотеку ImageCache.
Вот полное описание droidfu и WebImageView: http://brainflush.wordpress.com/2009/11/23/droid-fu-part-2-webimageview-and-webgalleryadapter/
Ответ 7
Я попробовал SoftReferences, они слишком агрессивно исправлены в андроиде, и я чувствовал, что им нечего использовать
Ответ 8
Как предложил Thunder Rabbit, ImageDownloader является лучшим для работы. Я также нашел небольшое изменение класса при:
http://theandroidcoder.com/utilities/android-image-download-and-caching/
Основное различие между ними заключается в том, что ImageDownloader использует систему кэширования Android, а модифицированный использует внутреннее и внешнее хранилище в качестве кеширования, сохраняя кешированные изображения неограниченно или до тех пор, пока пользователь не удалит его вручную. Автор также упоминает совместимость с Android 2.1.
Ответ 9
Это хороший улов Джо. В приведенном выше примере кода есть две проблемы: одна - объект ответа не является экземпляром 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
Я по-прежнему считаю, что это решение OK для этого маршрута - но вам все равно придется писать кеш. Звучит весело, но я предпочитаю писать функции.
Ответ 10
В официальной секции обучения 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), данные поддержки растрового изображения были сохранены в память, которая не будет выпущена предсказуемым образом, потенциально заставляя приложение в кратчайшие сроки превышать его пределы памяти и сбой.
Ответ 11
Рассмотрите возможность использования библиотеки универсального загрузчика изображений Сергей Тарасевич. Он поставляется с:
- Загрузка многопоточных изображений. Он позволяет определить размер пула потоков
- Кэширование изображений в памяти, на файловой системе устройства и SD-карте.
- Возможность прослушивания загрузки и загрузки событий
Универсальный загрузчик изображений позволяет подробное управление кешем для загруженных изображений со следующими конфигурациями кеша:
-  UsingFreqLimitedMemoryCache: используемое растровое изображение наименее часто удаляется при превышении лимита размера кеша.
-  LRULimitedMemoryCache: Используемый растровый файл менее недавно удаляется при превышении лимита размера кеша.
-  FIFOLimitedMemoryCache: правило FIFO используется для удаления при превышении лимита размера кеша.
-  LargestLimitedMemoryCache: Максимальное растровое изображение удаляется при превышении лимита размера кеша.
-  LimitedAgeMemoryCache: объект Cached удаляется, когда его возраст превышает определенное значение.
-  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 по умолчанию.
Ответ 12
Что на самом деле сработало для меня, это установка 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
Ответ 13
У Google libs-for-android есть хорошие библиотеки для управления кэшем изображений и файлов.
Ответ 14
Я боролся с этим в течение некоторого времени; ответы с использованием SoftReferences потеряли бы свои данные слишком быстро. Ответы, которые предполагают создание экземпляра RequestCache, были слишком грязными, и я никогда не смог найти полный пример.
Но ImageDownloader.java отлично работает для меня. Он использует HashMap до тех пор, пока не будет достигнута пропускная способность или пока не произойдет тайм-аут очистки, затем все будет перемещено в SoftReference, тем самым используя лучшее из обоих миров.
Ответ 15
Я предлагаю IGNITION, это даже лучше, чем Droid fu
https://github.com/kaeppler/ignition
https://github.com/kaeppler/ignition/wiki/Sample-applications
Ответ 16
Поздний ответ, но я решил, что должен добавить ссылку на мой сайт, потому что я написал учебник, как сделать кеш изображения для android:  http://squarewolf.nl/2010/11/android-image-cache/  Обновление: страница была отключена, поскольку источник устарел. Я присоединяюсь к @elenasys в ее совете, чтобы использовать Ignition.
Итак, всем людям, которые спотыкаются на этот вопрос и не нашли решения: надеюсь, вам понравится!= D
Ответ 17
Еще позже ответьте, но я написал Android Image Manager, который прозрачно выполняет кеширование (память и диск). Код находится на Github https://github.com/felipecsl/Android-ImageManager
