android - squareup - picasso kotlin
¿Cómo uso el almacenamiento en caché de disco en Picasso? (7)
Estoy usando Picasso para mostrar la imagen en mi aplicación de 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);
}
He habilitado la depuración y siempre muestra rojo o verde. Pero nunca aparece amarillo
Ahora, si cargo la misma imagen la próxima vez y no hay conexión a Internet, la imagen no se carga.
Preguntas:
- ¿No tiene caché de disco local?
- ¿Cómo habilito el almacenamiento en caché de disco, ya que usaré la misma imagen varias veces?
- ¿Debo agregar algún permiso de disco al archivo de manifiesto de Android?
1) Picasso por defecto tiene caché (ver ahmed hamdy answer)
2) Si realmente debe tomar una imagen de la memoria caché del disco y luego de la red, le recomiendo que escriba su propio programa de descarga:
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;
}
}
}
Y en Aplicación singleton en el método OnCreate, úsalo con 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) No se necesitan permisos para la carpeta de caché de la aplicación defalut
Agregue el código siguiente en Application.onCreate
luego úselo normalmente
Picasso picasso = new Picasso.Builder(context)
.downloader(new OkHttp3Downloader(this,Integer.MAX_VALUE))
.build();
picasso.setIndicatorsEnabled(true);
picasso.setLoggingEnabled(true);
Picasso.setSingletonInstance(picasso);
Si primero ProductImageDownloader.doBackground
en caché las imágenes, haga algo como esto en 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);
}
y cargue sus imágenes como normal o con el almacenamiento en caché de disco
Picasso.with(this).load(Constants.imagesUrl+batterProduct.getGalleryImage())
.networkPolicy(NetworkPolicy.OFFLINE)
.placeholder(R.drawable.GalleryDefaultImage)
.error(R.drawable.GalleryDefaultImage)
.into(viewGallery);
Nota:
El color rojo indica que la imagen se obtiene de la red .
El color verde indica que la imagen se obtiene de la memoria caché .
El color azul indica que la imagen se obtiene de la memoria del disco .
Antes de liberar la aplicación, elimínela o picasso.setLoggingEnabled(true);
como false
picasso.setLoggingEnabled(true);
, picasso.setIndicatorsEnabled(true);
si no es requerido Thankx
Esto es lo que hice. Funciona bien.
Primero agregue el OkHttp al archivo de compilación gradle del módulo de la aplicación:
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''
Luego haga una Application
extensión de clase
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);
}
}
agréguelo al archivo Manifiesto de la siguiente manera:
<application
android:name=".Global"
.. >
</application>
Ahora usa Picasso como lo harías normalmente. Sin cambios.
EDITAR:
si solo quieres usar imágenes en caché. Llame a la biblioteca de esta manera. Me he dado cuenta de que si no agregamos NetworkPolicy, las imágenes no se mostrarán en un inicio completamente fuera de línea, incluso si están en caché . El siguiente código resuelve el problema.
Picasso.with(this)
.load(url)
.networkPolicy(NetworkPolicy.OFFLINE)
.into(imageView);
EDIT # 2
El problema con el código anterior es que si borras el caché, Picasso lo seguirá buscando sin conexión en el caché y fallará, el siguiente ejemplo de código examina el caché local, si no se encuentra fuera de línea, se conecta y repone el caché.
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");
}
});
}
});
Para el almacenamiento en caché, utilizaría interceptores OkHttp para obtener control sobre la política de almacenamiento en caché. Vea esta muestra que está incluida en la biblioteca OkHttp.
Así es como lo usaría con Picasso:
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);
Tuve el mismo problema y usé la biblioteca Glide en su lugar. La memoria caché está fuera de la caja allí. https://github.com/bumptech/glide
Uso este código y funcionó, tal vez sea útil para ti:
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...");
}
});
}
});
}
1) respuesta de la primera pregunta: según el método de Picasso Doc for With ()
La instancia global predeterminada de Picasso devuelta desde () se inicializa automáticamente con los valores predeterminados que son adecuados para la mayoría de las implementaciones.
- Memoria caché LRU del 15% de la RAM de la aplicación disponible
- Caché de disco de 2% de espacio de almacenamiento de hasta 50 MB pero no menos de 5 MB.
Pero la operación de Disk Cache
para Global Default Picasso solo está disponible en API 14+
2) respuesta de la segunda Pregunta: Picasso
utiliza la solicitud del cliente HTTP
para la operación de Disk Cache
Así puede hacer que su propio http request header
tenga la propiedad Cache-Control
con max-age
Cree su propia instancia de Static Picasso en lugar de Picasso predeterminado.
1] HttpResponseCache (Nota: funciona solo para API 13+)
2] OkHttpClient (funciona para todas las API)
Ejemplo para usar OkHttpClient
para crear su propia clase Static Picasso:
Primero crea una nueva clase para obtener tu propio objeto 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; } }
use su propio objeto singleton
picasso
lugar dePicasso.With()
PicassoCache.getPicassoInstance(getContext()).load(imagePath).into(imageView)
3) respuesta para la tercera pregunta: no necesita ningún permiso de disco para las operaciones de caché de disco
Referencias : problema de Github sobre el caché de disco , dos preguntas han sido respondidas por @jake-wharton -> Question1 y Question2