web-dev-qa-db-fra.com

Comment utiliser la mise en cache de disque dans Picasso?

J'utilise Picasso pour afficher des images dans mon application 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);
}

J'ai activé le débogage et il montre toujours soit le rouge et le vert. Mais ne montre jamais le jaune

Maintenant, si je charge la même image la prochaine fois et Internet n'est pas disponible, l'image n'est pas chargée.

Des questions:

  1. N'a-t-il pas un cache de disque local?
  2. Comment puis-je activer la mise en cache du disque, car j'utiliserai la même image plusieurs fois.
  3. Dois-je ajouter une autorisation de disque au fichier de manifeste Android?
103
user93796

C'est ce que j'ai fait. Fonctionne bien.

Commencez par ajouter OkHttp au fichier de construction Gradle du module d'application: 

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'

Faites ensuite un cours qui étend 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);

    }
}

ajoutez-le au fichier Manifest comme suit:

<application
        Android:name=".Global"
        .. >

</application>

Maintenant, utilisez Picasso comme vous le feriez normalement. Aucun changement.

MODIFIER:

si vous souhaitez utiliser uniquement les images en cache. Appelez la bibliothèque comme ça. J'ai remarqué que si nous n'ajoutons pas networkPolicy, les images ne s'afficheront pas dans un démarrage totalement hors ligne même si elles sont mises en cache . Le code ci-dessous résout le problème.

Picasso.with(this)
            .load(url)
            .networkPolicy(NetworkPolicy.OFFLINE)
            .into(imageView);

EDIT # 2

le problème avec le code ci-dessus est que si vous effacez le cache, Picasso continuera à le rechercher hors ligne dans le cache et échouera. L'exemple de code suivant examine le cache local. S'il n'est pas trouvé hors connexion, il passe en ligne et reconstitue le cache.

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");
            }
        });
    }
});
211
Sanket Berde

Pour la mise en cache, je voudrais utiliser OkHttp interceptors pour prendre le contrôle de la politique de mise en cache. Découvrez cet exemple inclus dans la bibliothèque OkHttp.

https://github.com/square/okhttp/blob/master/samples/guide/src/main/Java/com/squareup/okhttp/recipes/RewriteResponseCacheControl.Java

Voici comment je l'utiliserais avec 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);
21
Gaurav B

1) Picasso a par défaut un cache (voir la réponse de ahmed hamdy)

2) Si vous devez vraiment prendre l’image du cache disque puis du réseau, je vous recommande d’écrire votre propre téléchargeur:

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;
        }

    }
}

Et dans Application singleton dans la méthode OnCreate, utilisez-le avec 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) Aucune autorisation requise pour le dossier de cache de l'application defalut

6
tsm

Pour la version la plus récente, 2.71828, voici votre réponse.

Q1: N'a-t-il pas de cache disque local?

A1: Il y a une mise en cache par défaut dans Picasso et le flux de demandes est comme celui-ci.

App -> Memory -> Disk -> Server

Partout où ils ont rencontré leur image en premier, ils utiliseront cette image puis arrêteront le flux de demandes. Qu'en est-il du flux de réponse? Ne t'inquiète pas, la voici.

Server -> Disk -> Memory -> App

Par défaut, ils vont d'abord stocker sur un disque local pour le cache de conservation étendu. Ensuite, la mémoire, pour l'utilisation d'instance du cache.

Vous pouvez utiliser l'indicateur intégré dans Picasso pour voir où les images se forment en l'activant.

Picasso.get().setIndicatorEnabled(true);

Un drapeau apparaîtra dans le coin supérieur gauche de vos photos.

  • Rouge indicateur signifie que les images proviennent du serveur. (Pas de cache au premier chargement)
  • Ble indicateur signifie que les photos proviennent du disque local. (Caching)
  • Vert indicateur signifie que les images proviennent de la mémoire. (Mise en cache d'instance)

Q2: Comment puis-je activer la mise en cache du disque car j'utiliserai la même image plusieurs fois?

A2: Vous n'êtes pas obligé de l'activer. C'est le défaut.

Ce que vous devez faire, c'est DISABLE lorsque vous voulez que vos images soient toujours fraîches. Il y a 2 sens de la mise en cache désactivée.

  1. Définissez .memoryPolicy() sur NO_CACHE et/ou NO_STORE et le flux va ressembler à ceci.

NO_CACHE ignorera la recherche d'images de la mémoire.

App -> Disk -> Server

NO_STORE ignorera les images stockées en mémoire lors du premier chargement d'images.

Server -> Disk -> App
  1. Définissez .networkPolicy() sur NO_CACHE et/ou NO_STORE et le flux va ressembler à ceci.

NO_CACHE ignorera la recherche d'images à partir du disque.

App -> Memory -> Server

NO_STORE ignorera les images stockées sur le disque lors du premier chargement d'images.

Server -> Memory -> App

Vous pouvez DISABLE ni pour l'absence totale d'images en cache. Voici un exemple.

Picasso.get().load(imageUrl)
             .memoryPolicy(MemoryPolicy.NO_CACHE,MemoryPolicy.NO_STORE)
             .networkPolicy(NetworkPolicy.NO_CACHE, NetworkPolicy.NO_STORE)
             .fit().into(banner);

Le flux de l'absence totale de cache et de stockage ressemblera à ceci.

App -> Server //Request

Server -> App //Response

Ainsi, vous aurez peut-être besoin de cela pour réduire également l'utilisation de votre stockage d'application.

Q: Dois-je ajouter une autorisation de disque au fichier manifeste Android?

A: Non, mais n'oubliez pas d'ajouter l'autorisation INTERNET pour votre requête HTTP.

1
Narerit Rittiplaeng

J'utilise ce code et travaille, peut-être utile pour vous:

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...");
                                }

                            });
                }
            });

}
0
Iman Marashi

Ajoutez le code suivant dans Application.onCreate puis utilisez-le normalement

    Picasso picasso = new Picasso.Builder(context)
            .downloader(new OkHttp3Downloader(this,Integer.MAX_VALUE))
            .build();
    picasso.setIndicatorsEnabled(true);
    picasso.setLoggingEnabled(true);
    Picasso.setSingletonInstance(picasso);

Si vous mettez d'abord les images en cache, faites quelque chose comme ceci dans 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);
        }

et chargez vos images comme d'habitude ou avec la mise en cache disque

    Picasso.with(this).load(Constants.imagesUrl+batterProduct.getGalleryImage())
        .networkPolicy(NetworkPolicy.OFFLINE)
        .placeholder(R.drawable.GalleryDefaultImage)
        .error(R.drawable.GalleryDefaultImage)
        .into(viewGallery);

Remarque: 

Rouge couleur indique que l'image est extraite de réseau .

Vert couleur indique que l'image est extraite de mémoire cache .

Bleu couleur indique que l'image est extraite de mémoire de disque .

Avant de publier l'application, supprimez-la ou définissez-la falsepicasso.setLoggingEnabled(true);, picasso.setIndicatorsEnabled(true); si non requis. Thankx

0
Qamar