如何在Picasso中使用磁盘缓存?

use*_*796 116 android caching image 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);
}
Run Code Online (Sandbox Code Playgroud)

我已启用调试,它始终显示红色和绿色.但从不显示黄色

现在,如果我下次加载相同的图像并且互联网不可用,则不会加载图像.

问题:

  1. 它没有本地磁盘缓存吗?
  2. 如何启用磁盘缓存,因为我将多次使用相同的图像.
  3. 我需要为android清单文件添加一些磁盘权限吗?

San*_*rde 226

这就是我做的.效果很好.

首先将OkHttp添加到app模块的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'
Run Code Online (Sandbox Code Playgroud)

然后进行课程扩展 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);

    }
}
Run Code Online (Sandbox Code Playgroud)

将它添加到Manifest文件,如下所示:

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

</application>
Run Code Online (Sandbox Code Playgroud)

现在像往常一样使用毕加索.没有变化.

编辑:

如果您只想使用缓存图像.像这样调用库.我注意到,如果我们不添加networkPolicy,即使缓存它们,图像也不会在完全脱机启动时显示.下面的代码解决了这个问题.

Picasso.with(this)
            .load(url)
            .networkPolicy(NetworkPolicy.OFFLINE)
            .into(imageView);
Run Code Online (Sandbox Code Playgroud)

编辑#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");
            }
        });
    }
});
Run Code Online (Sandbox Code Playgroud)

  • @SanketBerde:感谢快速注释,但我发现只有当应用程序在后台运行时(离线时),图像才会从内存中传出.如果我关闭应用程序,那么运行的应用程序很清楚,然后再次打开我的应用程序,图像不会从缓存中加载.我已设置即将出现的错误默认加载图像.这可能有什么问题? (4认同)
  • 谢谢它的工作.为什么它不是公认的答案? (2认同)

ahm*_*mdy 45

1)第一个问题的答案:根据Picasso Doc for With()方法

从with()返回的全局默认Picasso实例使用适合大多数实现的默认值自动初始化.

  • LRU内存缓存可用应用程序RAM的15%
  • 2%存储空间的磁盘缓存高达50MB但不低于5MB.

Disk Cache全球默认毕加索的操作仅适用于API 14+

2)第二个问题的答案是:Picasso使用HTTP客户端请求Disk Cache的操作所以你可以使自己http request header拥有产权Cache-Controlmax-age 开创自己的静态毕加索实例,而不是默认的毕加索通过使用

1] HttpResponseCache(注意:仅适用于API 13+)
2] OkHttpClient(适用于所有API)

用于OkHttpClient创建自己的Static Picasso类的示例:

  • 首先创建一个新类来获取自己的单例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;
        }
    
    } 
    
    Run Code Online (Sandbox Code Playgroud)
  • 使用你自己的单例picasso对象而不是Picasso.With()

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

3)回答第三个问题:磁盘缓存操作不需要任何磁盘权限

参考文献:关于磁盘缓存的Github问题,@ jake-wharton已经回答了两个问题- > 问题1问题2

  • 不,如果app关闭,这不起作用.应用程序被强制停止后,所有图像都消失了. (4认同)
  • 这给了我这个错误:`FATAL EXCEPTION:main java.lang.NoClassDefFoundError:com.squareup.okhttp.OkHttpClient` (2认同)

Gau*_*v B 21

对于缓存,我会使用OkHttp 拦截器来控制缓存策略.查看OkHttp库中包含的此示例.

https://github.com/square/okhttp/blob/master/samples/guide/src/main/java/com/squareup/okhttp/recipes/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);
Run Code Online (Sandbox Code Playgroud)


Nar*_*eng 18

对于最新版本 2.71828 这些就是您的答案。

Q1 : 它没有本地磁盘缓存吗?

A1 : Picasso 中有默认缓存,请求流程就像这样

App -> Memory -> Disk -> Server
Run Code Online (Sandbox Code Playgroud)

无论他们在哪里首先遇到他们的图像,他们都会使用该图像,然后停止请求流。响应流呢?别担心,它来了。

Server -> Disk -> Memory -> App
Run Code Online (Sandbox Code Playgroud)

默认情况下,它们将首先存储到本地磁盘中以用于扩展保持缓存。然后是内存,用于缓存的实例使用。

您可以使用 Picasso 中的内置指示器通过启用它来查看图像的形成位置。

Picasso.get().setIndicatorEnabled(true);
Run Code Online (Sandbox Code Playgroud)

它会在图片的左上角显示一个标志。

  • 红色标志意味着图像来自于服务器。(第一次加载时不缓存)
  • 蓝色标志意味着该照片来自本地磁盘。(缓存)
  • 绿旗表示图像来自内存。(实例缓存)

Q2:我将多次使用同一个图像,如何启用磁盘缓存?

A2:您不必启用它。这是默认设置。

当您希望图像始终保持新鲜时,您需要做的是禁用它。有两种禁用缓存的方式。

  1. 设置.memoryPolicy()NO_CACHE和/或NO_STORE,流程将如下所示。

NO_CACHE将跳过从内存中查找图像。

App -> Disk -> Server
Run Code Online (Sandbox Code Playgroud)

NO_STORE将在第一次加载图像时跳过将图像存储在内存中。

Server -> Disk -> App
Run Code Online (Sandbox Code Playgroud)
  1. 设置.networkPolicy()NO_CACHE和/或NO_STORE,流程将如下所示。

NO_CACHE将跳过从磁盘查找图像。

App -> Memory -> Server
Run Code Online (Sandbox Code Playgroud)

NO_STORE将在第一次加载图像时跳过存储在磁盘中的图像。

Server -> Memory -> App
Run Code Online (Sandbox Code Playgroud)

您可以DISABLE两者都不完全不缓存图像。这是一个例子。

Picasso.get().load(imageUrl)
             .memoryPolicy(MemoryPolicy.NO_CACHE,MemoryPolicy.NO_STORE)
             .networkPolicy(NetworkPolicy.NO_CACHE, NetworkPolicy.NO_STORE)
             .fit().into(banner);
Run Code Online (Sandbox Code Playgroud)

完全无缓存和无存储的流程将如下所示。

App -> Server //Request

Server -> App //Response
Run Code Online (Sandbox Code Playgroud)

因此,您可能还需要它来减少您的应用程序存储使用量。

问题 3:我需要为 android manifest 文件添加一些磁盘权限吗?

A3 : 不,但不要忘记为您的 HTTP 请求添加 INTERNET 权限。


小智 6

1)Picasso默认有缓存(见ahmed hamdy的答案)

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

    }
}
Run Code Online (Sandbox Code Playgroud)

在应用程序单例中,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);
Run Code Online (Sandbox Code Playgroud)

3)defalut应用程序缓存文件夹不需要权限