Android 如何在 Picasso 中使用磁盘缓存?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/23978828/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do I use disk caching in Picasso?
提问by user93796
I am using Picasso to display image in my android app:
我正在使用 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);
}
I have enable debugging and it always shows either red and green .But never shows yellow
我启用了调试,它总是显示红色和绿色。但从不显示黄色
Now if i load same image next time and internet is not available the image is not loaded.
现在,如果我下次加载相同的图像并且互联网不可用,则不会加载图像。
Questions:
问题:
- Does it not have local disk cache?
- How do i enable disk caching as i will be using same image multiple times.
- Do i need to add some disk permission to android manifest file?
- 它没有本地磁盘缓存吗?
- 我如何启用磁盘缓存,因为我将多次使用相同的图像。
- 我需要为android清单文件添加一些磁盘权限吗?
回答by Sanket Berde
This is what I did. Works well.
这就是我所做的。效果很好。
First add the OkHttp to the gradle build file of the app module:
首先将 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'
Then make a class extending Application
然后做一个类扩展 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 :
将其添加到 Manifest 文件中,如下所示:
<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 upin an fully offline start even if they are cached. The code below solves the problem.
如果您只想使用缓存图像。像这样调用图书馆。我注意到,如果我们不添加 networkPolicy,即使图像被缓存,图像也不会在完全脱机启动时显示。下面的代码解决了这个问题。
Picasso.with(this)
.load(url)
.networkPolicy(NetworkPolicy.OFFLINE)
.into(imageView);
EDIT #2
编辑#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会一直在缓存中离线查找并失败,下面的代码示例查看本地缓存,如果离线找不到,则在线并补充缓存。
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");
}
});
}
});
回答by ahmed hamdy
1)answer of first question : according to Picasso Doc for With() method
1)第一个问题的答案:根据Picasso Doc for With() 方法
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.
从 with() 返回的全局默认 Picasso 实例会自动初始化为适用于大多数实现的默认值。
- 可用应用程序 RAM 的 15% 的 LRU 内存缓存
- 2% 存储空间的磁盘缓存,最高 50MB 但不低于 5MB。
ButDisk Cache
operation for global Default Picasso is only available on API 14+
但是Disk Cache
全局 Default Picasso 的操作仅在 API 14+ 上可用
2)answer of second Question : Picasso
use the HTTP
client request to Disk Cache
operation Soyou 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
2)第二个问题的答案是:Picasso
使用HTTP
客户端请求Disk Cache
的操作所以你可以使自己http request header
拥有产权Cache-Control
与max-age
并创建自己的静态毕加索实例,而不是默认的毕加索通过使用
1] HttpResponseCache(Note: Works only for API 13+ )
2] OkHttpClient(Works for all APIs)
1] HttpResponseCache(注意:仅适用于 API 13+)
2] OkHttpClient(适用于所有 API)
Examplefor using OkHttpClient
to create your own Static Picasso class:
用于OkHttpClient
创建您自己的静态毕加索类的示例:
First create a new class to get your own singleton
picasso
objectimport 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 ofPicasso.With()
首先创建一个新类来获取自己的单例
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; } }
使用你自己的单例
picasso
对象而不是Picasso.With()
PicassoCache.getPicassoInstance(getContext()).load(imagePath).into(imageView)
PicassoCache.getPicassoInstance(getContext()).load(imagePath).into(imageView)
3)answer for third question : you do not need any disk permissions for disk Cache operations
3)回答第三个问题:磁盘缓存操作不需要任何磁盘权限
References: Github issue about disk cache, two Questions has been answered by @jake-wharton-> Question1and Question2
参考:关于磁盘缓存的 Github 问题,@jake-wharton已经回答了两个问题-> Question1和Question2
回答by Gaurav B
For caching, I would use OkHttp interceptorsto gain control over caching policy. Check out this sample that's included in the OkHttp library.
对于缓存,我会使用 OkHttp拦截器来控制缓存策略。查看包含在 OkHttp 库中的这个示例。
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);
回答by Narerit Rittiplaeng
For the most updated version 2.71828 These are your answer.
对于最新版本 2.71828 这些就是您的答案。
Q1: Does it not have local disk cache?
Q1: 它没有本地磁盘缓存吗?
A1: There is default caching within Picasso and the request flow just like this
A1: Picasso 中有默认缓存,请求流程就像这样
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 中的内置指示器通过启用它来查看图像的形成位置。
Picasso.get().setIndicatorEnabled(true);
It will show up a flag on the top left corner of your pictures.
它会在图片的左上角显示一个标志。
- Redflag means the images come from the server. (No caching at first load)
- Blueflag means the photos come from the local disk. (Caching)
- Greenflag 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?
Q2:我将多次使用同一个图像,如何启用磁盘缓存?
A2: You don't have to enable it. It's the default.
A2:您不必启用它。这是默认设置。
What you'll need to do is DISABLEit when you want your images always fresh. There is 2-way of disabled caching.
当您希望图像始终保持新鲜时,您需要做的是禁用它。有两种禁用缓存的方式。
- Set
.memoryPolicy()
to NO_CACHEand/or NO_STOREand the flow will look like this.
- 设置
.memoryPolicy()
为NO_CACHE和/或NO_STORE,流程将如下所示。
NO_CACHEwill skip looking up images from memory.
NO_CACHE将跳过从内存中查找图像。
App -> Disk -> Server
NO_STOREwill skip store images in memory when the first load images.
NO_STORE将在第一次加载图像时跳过将图像存储在内存中。
Server -> Disk -> App
- Set
.networkPolicy()
to NO_CACHEand/or NO_STOREand the flow will look like this.
- 设置
.networkPolicy()
为NO_CACHE和/或NO_STORE,流程将如下所示。
NO_CACHEwill skip looking up images from disk.
NO_CACHE将跳过从磁盘查找图像。
App -> Memory -> Server
NO_STOREwill skip store images in the disk when the first load images.
NO_STORE将在第一次加载图像时跳过存储在磁盘中的图像。
Server -> Memory -> App
You can DISABLEneither for fully no caching images. Here is an example.
您可以DISABLE两者都不完全不缓存图像。这是一个例子。
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?
问题 3:我需要为 android manifest 文件添加一些磁盘权限吗?
A3: No, but don't forget to add the INTERNET permission for your HTTP request.
A3: 不,但不要忘记为您的 HTTP 请求添加 INTERNET 权限。
回答by tsm
1) Picasso by default has cache (see ahmed hamdy answer)
1) Picasso 默认有缓存(见 ahmed hamdy 的回答)
2) If your really must take image from disk cache and then network I recommend to write your own downloader:
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;
}
}
}
And in Application singleton in method OnCreate use it with picasso:
在方法 OnCreate 中的应用程序单例中,将它与毕加索一起使用:
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
3)默认应用程序缓存文件夹不需要权限
回答by Qamar
Add followning code in Application.onCreate
then use it normal
添加以下代码Application.onCreate
然后正常使用
Picasso picasso = new Picasso.Builder(context)
.downloader(new OkHttp3Downloader(this,Integer.MAX_VALUE))
.build();
picasso.setIndicatorsEnabled(true);
picasso.setLoggingEnabled(true);
Picasso.setSingletonInstance(picasso);
If you cache images first then do something like this in ProductImageDownloader.doBackground
如果您先缓存图像,然后在 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);
}
and load your images like normal or with disk caching
并像平常一样加载您的图像或使用磁盘缓存
Picasso.with(this).load(Constants.imagesUrl+batterProduct.getGalleryImage())
.networkPolicy(NetworkPolicy.OFFLINE)
.placeholder(R.drawable.GalleryDefaultImage)
.error(R.drawable.GalleryDefaultImage)
.into(viewGallery);
Note:
笔记:
Redcolor indicates that image is fetched from network.
红色表示图像是从网络获取的。
Greencolor indicates that image is fetched from cache memory.
绿色表示图像是从缓存中获取的。
Bluecolor indicates that image is fetched from disk memory.
蓝色表示图像是从磁盘内存中获取的。
Before releasing the app delete or set it false
picasso.setLoggingEnabled(true);
, picasso.setIndicatorsEnabled(true);
if not required. Thankx
如果不需要false
picasso.setLoggingEnabled(true);
,在发布应用程序之前删除或设置它picasso.setIndicatorsEnabled(true);
。谢谢
回答by Iman Marashi
I use this code and worked, maybe useful for you:
我使用此代码并工作,可能对您有用:
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...");
}
});
}
});
}
回答by Abhinav Chauhan
I don't know how good that solution is but it is definitely THE EASY ONEi just used in my app and it is working fine
我不知道该解决方案有多好,但它绝对是我刚刚在我的应用程序中使用的最简单的解决方案,并且运行良好
you load the image like that
你像这样加载图像
public void loadImage (){
Picasso picasso = Picasso.with(this);
picasso.setDebugging(true);
picasso.load(quiz.getImageUrl()).into(quizImage);
}
You can't get the bimap
like that
你不能得到bimap
那样的
Bitmap bitmap = Piccaso.with(this).load(quiz.getImageUrl()).get();
Now covert that Bitmap
into a JPG
file and store in the in the cache, below is complete code for getting the bimap and caching it
现在将其Bitmap
转换为JPG
文件并存储在缓存中,下面是获取双映射并缓存它的完整代码
Thread thread = new Thread() {
public void run() {
File file = new File(getActivity().getExternalCacheDir().getAbsolutePath() + "/" +member.getMemberId() + ".jpg");
try {
Bitmap bitmap = Picasso.with(getActivity())
.load(uri).get();
bitmap.compress(Bitmap.CompressFormat.JPEG, 100,new FileOutputStream(file));
} catch (Exception e) {
e.printStackTrace();
}
}
};
thread.start();
})
the get()
method of Piccasso
needed to be called on separate thread , i am saving that image also on that same thread.
需要在单独的线程上调用的get()
方法Piccasso
,我也在同一个线程上保存该图像。
Once the image is saved you can get all the files like that
保存图像后,您可以获得所有这样的文件
List<File> files = new LinkedList<>(Arrays.asList(context.getExternalCacheDir().listFiles()));
now you can find the file you are looking for like below
现在你可以找到你正在寻找的文件,如下所示
for(File file : files){
if(file.getName().equals("fileyouarelookingfor" + ".jpg")){ // you need the name of the file, for example you are storing user image and the his image name is same as his id , you can call getId() on user to get the file name
Picasso.with(getActivity()) // if file found then load it
.load(file)
.into(mThumbnailImage);
return; // return
}
// fetch it over the internet here because the file is not found
}
回答by qbait
I had the same problem and used Glide library instead. Cache is out of the box there. https://github.com/bumptech/glide
我遇到了同样的问题,而是使用了 Glide 库。缓存是开箱即用的。 https://github.com/bumptech/glide