Как использовать кеширование диска в Picasso?
Я использую Picasso для отображения изображения в приложении для Android:
/**
* load image.This is within a activity so this context is activity
*/
public void loadImage (){
Picasso picasso = Picasso.with(this);
picasso.setDebugging(true);
picasso.load(quiz.getImageUrl()).into(quizImage);
}
У меня есть возможность отладки и всегда отображается как красный, так и зеленый. Но никогда не отображается желтый цвет
Теперь, если я загружаю одно и то же изображение в следующий раз, и интернет недоступен, изображение не загружается.
Вопросы:
- Не имеет ли кэш локального диска?
- Как включить кеширование диска, поскольку я буду использовать одно и то же изображение несколько раз.
- Нужно ли мне добавить диск в файл манифеста Android?
Ответы
Ответ 1
Это то, что я сделал. Работает хорошо.
Сначала добавьте OkHttp в файл сборки Gradle модуля приложения:
compile 'com.squareup.picasso:picasso:2.5.2'
compile 'com.squareup.okhttp3:okhttp:3.10.0'
compile 'com.jakewharton.picasso:picasso2-okhttp3-downloader:1.1.0'
Затем создайте класс, расширяющий Application
import android.app.Application;
import com.jakewharton.picasso.OkHttp3Downloader;
import com.squareup.picasso.Picasso;
public class Global extends Application {
@Override
public void onCreate() {
super.onCreate();
Picasso.Builder builder = new Picasso.Builder(this);
builder.downloader(new OkHttp3Downloader(this,Integer.MAX_VALUE));
Picasso built = builder.build();
built.setIndicatorsEnabled(true);
built.setLoggingEnabled(true);
Picasso.setSingletonInstance(built);
}
}
добавьте его в файл манифеста следующим образом:
<application
android:name=".Global"
.. >
</application>
Теперь используйте Пикассо, как обычно. Без изменений.
РЕДАКТИРОВАТЬ:
если вы хотите использовать только кэшированные изображения. Позвони в библиотеку вот так. Я заметил, что если мы не добавим networkPolicy, изображения не будут отображаться при полностью автономном запуске, даже если они кэшируются. Код ниже решает проблему.
Picasso.with(this)
.load(url)
.networkPolicy(NetworkPolicy.OFFLINE)
.into(imageView);
РЕДАКТИРОВАТЬ № 2
проблема с приведенным выше кодом заключается в том, что если вы очистите кеш, Picasso будет продолжать искать его в кеше в автономном режиме и завершится с ошибкой, в следующем примере кода рассматривается локальный кеш, если он не найден в автономном режиме, он подключается к сети и пополняет кеш.
Picasso.with(getActivity())
.load(imageUrl)
.networkPolicy(NetworkPolicy.OFFLINE)
.into(imageView, new Callback() {
@Override
public void onSuccess() {
}
@Override
public void onError() {
//Try again online if cache failed
Picasso.with(getActivity())
.load(posts.get(position).getImageUrl())
.error(R.drawable.header)
.into(imageView, new Callback() {
@Override
public void onSuccess() {
}
@Override
public void onError() {
Log.v("Picasso","Could not fetch image");
}
});
}
});
Ответ 2
1) ответ на первый вопрос:
согласно Метод Picasso для метода With()
Глобальный экземпляр Picasso по умолчанию, возвращаемый с помощью(), автоматически инициализируется значениями по умолчанию, которые подходят для большинства реализаций.
- Кэш LRU объемом 15% доступной оперативной памяти
- Кэш-память емкостью 2% памяти до 50 МБ, но не менее 5 МБ.
Но Disk Cache
операция для глобального По умолчанию Picasso доступна только в API 14 +
2) ответ второго вопроса: Picasso
используйте клиентский запрос HTTP
для Disk Cache
операции So, вы можете сделать свой собственный http request header
свойство Cache-Control
с max-age
И создайте свой собственный экземпляр Static Picasso вместо стандартного Picasso. Используя
1] HttpResponseCache (Примечание: работает только для API 13+)
2] OkHttpClient (работает для всех API)
Пример для использования OkHttpClient
для создания собственного класса Static Picasso:
-
Сначала создайте новый класс, чтобы получить собственный объект singleton Picasso
import android.content.Context;
import com.squareup.picasso.Downloader;
import com.squareup.picasso.OkHttpDownloader;
import com.squareup.picasso.Picasso;
public class PicassoCache {
/**
* Static Picasso Instance
*/
private static Picasso picassoInstance = null;
/**
* PicassoCache Constructor
*
* @param context application Context
*/
private PicassoCache (Context context) {
Downloader downloader = new OkHttpDownloader(context, Integer.MAX_VALUE);
Picasso.Builder builder = new Picasso.Builder(context);
builder.downloader(downloader);
picassoInstance = builder.build();
}
/**
* Get Singleton Picasso Instance
*
* @param context application Context
* @return Picasso instance
*/
public static Picasso getPicassoInstance (Context context) {
if (picassoInstance == null) {
new PicassoCache(context);
return picassoInstance;
}
return picassoInstance;
}
}
-
используйте собственный объект singleton Picasso
Вместо Picasso.With()
PicassoCache.getPicassoInstance(getContext()).load(imagePath).into(imageView)
3) ответ на третий вопрос: вам не нужны какие-либо разрешения на диск для операций с кешем диска
Ссылки: Проблема Github о кэше диска, на два вопроса ответил @jake-wharton → Question1 и Question2
Ответ 3
Для кэширования я бы использовал перехватчики OkHttp, чтобы получить контроль над политикой кэширования. Проверьте этот пример, который включен в библиотеку OkHttp.
RewriteResponseCacheControl.java
Вот как бы я использовал это с Пикассо -
OkHttpClient okHttpClient = new OkHttpClient();
okHttpClient.networkInterceptors().add(new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Response originalResponse = chain.proceed(chain.request());
return originalResponse.newBuilder().header("Cache-Control", "max-age=" + (60 * 60 * 24 * 365)).build();
}
});
okHttpClient.setCache(new Cache(mainActivity.getCacheDir(), Integer.MAX_VALUE));
OkHttpDownloader okHttpDownloader = new OkHttpDownloader(okHttpClient);
Picasso picasso = new Picasso.Builder(mainActivity).downloader(okHttpDownloader).build();
picasso.load(imageURL).into(viewHolder.image);
Ответ 4
1) Picasso по умолчанию имеет кеш (см. ahmed hamdy answer)
2) Если вы действительно должны взять изображение из дискового кеша, а затем сеть, я рекомендую написать собственный загрузчик:
public class OkHttpDownloaderDiskCacheFirst extends OkHttpDownloader {
public OkHttpDownloaderDiskCacheFirst(OkHttpClient client) {
super(client);
}
@Override
public Response load(Uri uri, int networkPolicy) throws IOException {
Response responseDiskCache = null;
try {
responseDiskCache = super.load(uri, 1 << 2); //NetworkPolicy.OFFLINE
} catch (Exception ignored){} // ignore, handle null later
if (responseDiskCache == null || responseDiskCache.getContentLength()<=0){
return super.load(uri, networkPolicy); //user normal policy
} else {
return responseDiskCache;
}
}
}
А в приложении singleton в методе OnCreate используйте его с picasso:
OkHttpClient okHttpClient = new OkHttpClient();
okHttpClient.setCache(new Cache(getCacheDir(), 100 * 1024 * 1024)); //100 MB cache, use Integer.MAX_VALUE if it is too low
OkHttpDownloader downloader = new OkHttpDownloaderDiskCacheFirst(okHttpClient);
Picasso.Builder builder = new Picasso.Builder(this);
builder.downloader(downloader);
Picasso built = builder.build();
Picasso.setSingletonInstance(built);
3) Разрешения, необходимые для папки кэша приложений defalut
Ответ 5
Я использую этот код и работал, возможно, полезен для вас:
public static void makeImageRequest(final View parentView,final int id, final String imageUrl) {
final int defaultImageResId = R.mipmap.user;
final ImageView imageView = (ImageView) parentView.findViewById(id);
Picasso.with(context)
.load(imageUrl)
.networkPolicy(NetworkPolicy.OFFLINE)
.into(imageView, new Callback() {
@Override
public void onSuccess() {
Log.v("Picasso","fetch image success in first time.");
}
@Override
public void onError() {
//Try again online if cache failed
Log.v("Picasso","Could not fetch image in first time...");
Picasso.with(context).load(imageUrl).networkPolicy(NetworkPolicy.NO_CACHE)
.memoryPolicy(MemoryPolicy.NO_CACHE, MemoryPolicy.NO_STORE).error(defaultImageResId)
.into(imageView, new Callback() {
@Override
public void onSuccess() {
Log.v("Picasso","fetch image success in try again.");
}
@Override
public void onError() {
Log.v("Picasso","Could not fetch image again...");
}
});
}
});
}
Ответ 6
Добавьте код followning в Application.onCreate
, затем используйте его normal
Picasso picasso = new Picasso.Builder(context)
.downloader(new OkHttp3Downloader(this,Integer.MAX_VALUE))
.build();
picasso.setIndicatorsEnabled(true);
picasso.setLoggingEnabled(true);
Picasso.setSingletonInstance(picasso);
Если вы сначала кэшируете изображения, тогда сделайте что-то вроде этого в ProductImageDownloader.doBackground
final Callback callback = new Callback() {
@Override
public void onSuccess() {
downLatch.countDown();
updateProgress();
}
@Override
public void onError() {
errorCount++;
downLatch.countDown();
updateProgress();
}
};
Picasso.with(context).load(Constants.imagesUrl+productModel.getGalleryImage())
.memoryPolicy(MemoryPolicy.NO_CACHE).fetch(callback);
Picasso.with(context).load(Constants.imagesUrl+productModel.getLeftImage())
.memoryPolicy(MemoryPolicy.NO_CACHE).fetch(callback);
Picasso.with(context).load(Constants.imagesUrl+productModel.getRightImage())
.memoryPolicy(MemoryPolicy.NO_CACHE).fetch(callback);
try {
downLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
if(errorCount == 0){
products.remove(productModel);
productModel.isDownloaded = true;
productsDatasource.updateElseInsert(productModel);
}else {
//error occurred while downloading images for this product
//ignore error for now
// FIXME: 9/27/2017 handle error
products.remove(productModel);
}
errorCount = 0;
downLatch = new CountDownLatch(3);
if(!products.isEmpty() /*&& testCount++ < 30*/){
startDownloading(products.get(0));
}else {
//all products with images are downloaded
publishProgress(100);
}
и загрузите изображения, как обычно, или с помощью кэширования диска
Picasso.with(this).load(Constants.imagesUrl+batterProduct.getGalleryImage())
.networkPolicy(NetworkPolicy.OFFLINE)
.placeholder(R.drawable.GalleryDefaultImage)
.error(R.drawable.GalleryDefaultImage)
.into(viewGallery);
Примечание:
Цвет Красный указывает, что изображение выбрано из сети.
Цвет Зеленый указывает, что изображение извлекается из кэш-памяти.
Цвет Синий указывает, что изображение извлекается из дисковой памяти.
Прежде чем отпустить приложение, удалите или установите его false
picasso.setLoggingEnabled(true);
, picasso.setIndicatorsEnabled(true);
, если это не требуется. Thankx
Ответ 7
Для самой последней версии 2.71828 Это ваш ответ.
Q1: у него нет локального дискового кэша?
A1: в Picasso есть кеширование по умолчанию и поток запросов, подобный этому
App -> Memory -> Disk -> Server
Где бы они ни встретили свое изображение в первую очередь, они будут использовать это изображение, а затем останавливают поток запросов. Как насчет потока ответов? Не волнуйся, вот оно.
Server -> Disk -> Memory -> App
По умолчанию они сначала сохраняются на локальном диске для расширенного хранения кеша. Затем память, для использования экземпляра кеша.
Вы можете использовать встроенный индикатор в Picasso, чтобы увидеть, где образуются изображения, включив это.
Picasso.get().setIndicatorEnabled(true);
Он покажет флаг в левом верхнем углу ваших фотографий.
- Красный флаг означает, что изображения поступают с сервера. (Нет кэширования при первой загрузке)
- Синий флаг означает, что фотографии пришли с локального диска. (Кэширование)
- Зеленый флаг означает, что изображения приходят из памяти. (Экземпляр Кэширование)
В2: Как включить кэширование на диске, так как я буду использовать одно и то же изображение несколько раз?
A2: Вам не нужно включать его. Это по умолчанию.
Что вам нужно сделать, это отключить его, когда вы хотите, чтобы ваши изображения всегда были свежими. Существует 2 способа отключения кэширования.
- Установите
.memoryPolicy()
в NO_CACHE и/или NO_STORE, и поток будет выглядеть следующим образом.
NO_CACHE пропустит поиск изображений из памяти.
App -> Disk -> Server
NO_STORE пропустит сохранение изображений в памяти при первой загрузке изображений.
Server -> Disk -> App
- Установите
.networkPolicy()
в NO_CACHE и/или NO_STORE, и поток будет выглядеть следующим образом.
NO_CACHE пропустит поиск изображений с диска.
App -> Memory -> Server
NO_STORE пропустит сохранение изображений на диске при первой загрузке изображений.
Server -> Memory -> App
Вы не можете отключить ни один, чтобы полностью не кэшировать изображения. Вот пример.
Picasso.get().load(imageUrl)
.memoryPolicy(MemoryPolicy.NO_CACHE,MemoryPolicy.NO_STORE)
.networkPolicy(NetworkPolicy.NO_CACHE, NetworkPolicy.NO_STORE)
.fit().into(banner);
Поток полностью без кеширования и хранения не будет выглядеть так.
App -> Server //Request
Server -> App //Response
Таким образом, вам может понадобиться это, чтобы минимизировать использование памяти вашего приложения.
Q3: мне нужно добавить некоторые права на диск в файл манифеста Android?
A3: Нет, но не забудьте добавить разрешение ИНТЕРНЕТ для вашего HTTP-запроса.
Ответ 8
У меня была такая же проблема, и я использовал библиотеку Glide. Там кеш из коробки. https://github.com/bumptech/glide