Используйте кэширование изображений LRU в сочетании с HTTPResponseCache для кэширования дисков и памяти
Первоначально цель состояла в том, чтобы использовать как кэш, так и диск. Это потребует реализации LRU-кеша и DiskLruCache. Однако, поскольку HTTPResponse кеш использует дисковое пространство, я решил использовать LRU кеш и сделать con.setUseCaches(true);
Проблема в том, что я не очень понимаю, что будет реализовано первым. Для кеша LRU и DiskLru это алгоритм:
т.е.
сначала проверьте кэш памяти для изображения
если есть изображение, верните его и обновите кэши
еще проверить кеш диска
если в кеше диска есть образ, верните его и обновите кеш
иначе скачайте образ из интернета, верните его и обновите кеш
Теперь с кодом ниже:
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;
Context mContext;
public DownloadImageTask(BaseAdapter adapter, int desiredWidth, int desiredHeight) {
this.adapter = adapter;
this.cache = ImagesCache.getInstance();
this.desiredWidth = desiredWidth;
this.desiredHeight = desiredHeight;
}
public DownloadImageTask(Context mContext, ImagesCache cache, ImageView ivImageView, int desireWidth, int desireHeight) {
this.cache = cache;
this.ivImageView = ivImageView;
this.desiredHeight = desireHeight;
this.desiredWidth = desireWidth;
this.mContext = mContext;
}
@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();
}
}
/*
* IMPORTANT:
* This enables your retrieval from the cache when working offline
*/
/***
* Force buffered operations to the filesystem. This ensures that responses
* written to the cache will be available the next time the cache is opened,
* even if this process is killed.
*/
HttpResponseCache cache = HttpResponseCache.getInstalled();
if(cache != null) {
//the number of HTTP requests issued since this cache was created.
Log.e("total num HTTP requests", String.valueOf(cache.getHitCount()));
//the number of those requests that required network use.
Log.e("num req network", String.valueOf(cache.getNetworkCount()));
//the number of those requests whose responses were served by the cache.
Log.e("num use cache", String.valueOf(cache.getHitCount()));
// If cache is present, flush it to the filesystem.
// Will be used when activity starts again.
cache.flush();
/***
* Uninstalls the cache and releases any active resources. Stored contents
* will remain on the filesystem.
*/
//UNCOMMENTING THIS PRODUCES A java.lang.IllegalStateException: cache is closedtry {
// cache.close();
//}
//catch(IOException e){
// e.printStackTrace();
//}
}
}
private Bitmap getImage(String imageUrl) {
if (cache.getImageFromWarehouse(imageUrl) == null) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
options.inSampleSize = inSampleSize;
//installing the cache at application startup.
try {
HttpResponseCache cache = HttpResponseCache.getInstalled();
if (cache == null) {
File httpCacheDir = new File(mContext.getCacheDir(), "http");
long HTTP_CACHE_SIZE_IN_BYTES = 1024 * 1024 * 1024; // 1GB
HttpResponseCache.install(httpCacheDir, HTTP_CACHE_SIZE_IN_BYTES);
//Log.e("Max DiskLRUCache Size", String.valueOf(DiskLruCache.getMaxSize());
}
}
catch (IOException e) {
e.printStackTrace();
}
try {
int readTimeout = 300000;
int connectTimeout = 300000;
URL url = new URL(imageUrl);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setUseCaches(true);
connection.addRequestProperty("Cache-Control", "max-stale=" + maxStale);
connection.setConnectTimeout(connectTimeout);
connection.setReadTimeout(readTimeout);
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();
connection.setUseCaches(true);
connection.addRequestProperty("Cache-Control", "only-if-cached");
connection.setConnectTimeout(connectTimeout);
connection.setReadTimeout(readTimeout);
stream = connection.getInputStream();
image = BitmapFactory.decodeStream(stream, null, options);
return image;
}
}
catch (Exception e) {
Log.e("getImage", e.toString());
}
}
return image;
}
}
Похоже, что в doInBackground() я сохраняю в HttpResponseCache, а в onPostExecute() я сохраняю то же изображение в LRUCache. Что я хотел бы сделать, это:
Если изображение не кэшировано, сохраните его в HttpResponseCache. Если HttpResponseCache заполнен, сохраните его в LRUCache. Если оба заполнены, используйте механизмы удаления по умолчанию, чтобы удалить старые неиспользуемые изображения. Проблема в том, чтобы сохранить оба кэша, а не
РЕДАКТИРОВАТЬ РЕФРЕЗОВЫЙ ВОПРОС
**
Поскольку оба кешируют одно и то же изображение, дважды и сохраняют кеш в одной и той же файловой системе, возможно, вопрос в том, какой из них использовать, поскольку нет смысла использовать оба...
**
1 ответ
Если кто-то захочет повторно использовать любой из вышеприведенного кода, я бы взял только кеш ответов http и не использовал кеш LRU, особенно если вы кешируете ответ веб-службы, например, JSON,xml. Зачем?
Однажды я потерял 200 МБ памяти устройства из-за описанной выше реализации кэша LRU.
Преимущества HTTPResponseCache:
- Кэширует ответы HTTP и HTTPS на файловую систему, чтобы их можно было повторно использовать, экономя время и пропускную способность.
- HttpUrlConnection делает: Автоматическая обработка механизмов кэширования,
- Ускоряет время отклика приложения с помощью HttpResponseCache
- Он доступен с уровня API 1=>, он выдержал испытание временем и надежен
С другой стороны:
Хотя у LRUCache есть свои преимущества перед DiskLRUCache:
- Вы должны реализовать класс (и другие вспомогательные классы), то есть, если код на Android-разработчиках изменится, вам придется постоянно загружать и редактировать локальную версию после того, как ваше приложение сломается после того, как предыдущая реализация была бы устаревшей.
- После удаления образа вы все равно можете обнаружить, что ваше дисковое пространство используется, так как образ будет где-то на вашем устройстве (как в моем случае).
Это вывод...