How do I use disk caching in Picasso?

前端 未结 9 788
-上瘾入骨i
-上瘾入骨i 2020-11-22 14:44

I am using Picasso to display image in my android app:

/**
* load image.This is within a activity so this context is activity
*/
public void loadImage (){
           


        
相关标签:
9条回答
  • 2020-11-22 15:15

    I had the same problem and used Glide library instead. Cache is out of the box there. https://github.com/bumptech/glide

    0 讨论(0)
  • 2020-11-22 15:22

    1) answer of first question : according to Picasso Doc for With() method

    The global default Picasso instance returned from with() is automatically initialized with defaults that are suitable to most implementations.

    • LRU memory cache of 15% the available application RAM
    • Disk cache of 2% storage space up to 50MB but no less than 5MB.

    But Disk Cache operation for global Default Picasso is only available on API 14+

    2) answer of second Question : Picasso use the HTTP client request to Disk Cache operation So you can make your own http request header has property Cache-Control with max-age And create your own Static Picasso Instance instead of default Picasso By using

    1] HttpResponseCache (Note: Works only for API 13+ )
    2] OkHttpClient (Works for all APIs)

    Example for using OkHttpClient to create your own Static Picasso class:

    • First create a new class to get your own singleton picasso object

      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 your own singleton picasso object Instead of Picasso.With()

    PicassoCache.getPicassoInstance(getContext()).load(imagePath).into(imageView)

    3) answer for third question : you do not need any disk permissions for disk Cache operations

    References: Github issue about disk cache, two Questions has been answered by @jake-wharton -> Question1 and Question2

    0 讨论(0)
  • 2020-11-22 15:26

    1) Picasso by default has cache (see ahmed hamdy answer)

    2) If your really must take image from disk cache and then network I recommend to write your own downloader:

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

    And in Application singleton in method OnCreate use it with 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 permissions needed for defalut application cache folder

    0 讨论(0)
  • 2020-11-22 15:31

    For caching, I would use OkHttp interceptors to gain control over caching policy. Check out this sample that's included in the OkHttp library.

    RewriteResponseCacheControl.java

    Here's how I'd use it with 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);
    
    0 讨论(0)
  • 2020-11-22 15:35

    This is what I did. Works well.

    First add the OkHttp to the gradle build file of the app module:

    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'
    

    Then make a class extending 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);
    
        }
    }
    

    add it to the Manifest file as follows :

    <application
            android:name=".Global"
            .. >
    
    </application>
    

    Now use Picasso as you normally would. No changes.

    EDIT:

    if you want to use cached images only. Call the library like this. I've noticed that if we don't add the networkPolicy, images won't show up in an fully offline start even if they are cached. The code below solves the problem.

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

    EDIT #2

    the problem with the above code is that if you clear cache, Picasso will keep looking for it offline in cache and fail, the following code example looks at the local cache, if not found offline, it goes online and replenishes the 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");
                }
            });
        }
    });
    
    0 讨论(0)
  • 2020-11-22 15:38

    For the most updated version 2.71828 These are your answer.

    Q1: Does it not have local disk cache?

    A1: There is default caching within Picasso and the request flow just like this

    App -> Memory -> Disk -> Server
    

    Wherever they met their image first, they'll use that image and then stop the request flow. What about response flow? Don't worry, here it is.

    Server -> Disk -> Memory -> App
    

    By default, they will store into a local disk first for the extended keeping cache. Then the memory, for the instance usage of the cache.

    You can use the built-in indicator in Picasso to see where images form by enabling this.

    Picasso.get().setIndicatorEnabled(true);
    

    It will show up a flag on the top left corner of your pictures.

    • Red flag means the images come from the server. (No caching at first load)
    • Blue flag means the photos come from the local disk. (Caching)
    • Green flag means the images come from the memory. (Instance Caching)

    Q2: How do I enable disk caching as I will be using the same image multiple times?

    A2: You don't have to enable it. It's the default.

    What you'll need to do is DISABLE it when you want your images always fresh. There is 2-way of disabled caching.

    1. Set .memoryPolicy() to NO_CACHE and/or NO_STORE and the flow will look like this.

    NO_CACHE will skip looking up images from memory.

    App -> Disk -> Server
    

    NO_STORE will skip store images in memory when the first load images.

    Server -> Disk -> App
    
    1. Set .networkPolicy() to NO_CACHE and/or NO_STORE and the flow will look like this.

    NO_CACHE will skip looking up images from disk.

    App -> Memory -> Server
    

    NO_STORE will skip store images in the disk when the first load images.

    Server -> Memory -> App
    

    You can DISABLE neither for fully no caching images. Here is an example.

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

    The flow of fully no caching and no storing will look like this.

    App -> Server //Request
    
    Server -> App //Response
    

    So, you may need this to minify your app storage usage also.

    Q3: Do I need to add some disk permission to android manifest file?

    A3: No, but don't forget to add the INTERNET permission for your HTTP request.

    0 讨论(0)
提交回复
热议问题