How do I use disk caching in Picasso?
Solution 1
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");
}
});
}
});
Solution 2
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
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()
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
Solution 3
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);
Solution 4
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.
- 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
- 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.
Solution 5
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
Sowmya Madras Rajesh
Updated on February 18, 2021Comments
-
Sowmya Madras Rajesh over 3 years
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 (){ 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?
-
nbumakov over 9 yearsNo, this isn't work if app was closed. After app was force stopped all images disappeared.
-
CIRCLE over 9 yearsthis is giving me this error:
FATAL EXCEPTION: main java.lang.NoClassDefFoundError: com.squareup.okhttp.OkHttpClient
-
ahmed hamdy over 9 years@CIRCLE sorry for late, To use Example,You need to download first [okhttp] (square.github.io/okhttp) package and [okio] (github.com/square/okio) package which used by
okhttp
-
ahmed hamdy over 9 years@CIRCLE may be you need to download [okhttp-urlconnection] (mvnrepository.com/artifact/com.squareup.okhttp/…) package too
-
Sanket Berde about 9 years@ArtjomB. , I did answer the question. And the solution does work. But there is this little clarification i can use. I went through the OkHttp documentation and they do not mention the unit of "cache". So if anyone would like to share some wisdom... this is a good opportunity.
-
Sanket Berde about 9 years@ArtjomB. yes that makes sense. Edited !
-
Admin almost 9 years@SanketBerde now i dont need to download images and check to exist in sdcard and show that into such as
ImageView
ok? -
TheDevMan almost 9 years@SanketBerde: Thanks for the quick note but I figured out the image is coming up from memory only if the App is running in background (when on offline). if I close the app, that is clear the running apps then open my app again the images don't load from Cache. I have set the error default loading image that is coming up. What could be wrong here?
-
Sanket Berde almost 9 years@TheDevMan yes even i noticed the problem.. i will post an edit supporting completely offline operation.
-
Sanket Berde almost 9 years@TheDevMan the first time you load an image on the app start, it will not come from cache, if you have previously downloaded it, it will come from disk and if you haven't, then from network.
-
Zhang over 8 yearsI got a crash about OkHttp, I also needed to include package OkHttp-URLConnection:
compile 'com.squareup.okhttp:okhttp-urlconnection:2.7.4'
to my gradle. -
Poras Bhardwaj about 8 years@Sanket Can I find/view these cached images on disk in Device. If yes, then in which directory? I have searched my Device File Explorer, but unable to find any cached image on disk.
-
Charu about 8 yearsThis is not working for me. Images are being reload each time when I scroll to their position in viewPager
-
ahmed hamdy about 8 years@charu you can use DEBUG INDICATORS feature in Picasso to figure image load from network or disk or memory. Call
setIndicatorsEnabled(true)
on the Picasso instance. for more details see official doc -
zeeshan about 8 yearsMaybe Picasso have changed how things work, because for me, it works fine without okhttp and network policy. On a new start, it instantly gets images from the disk, and when network is offline, it still shows them fine.
-
noev almost 8 yearsDoesn't work anymore networkInterceptors() returns an immutable list.
-
Gaurav B almost 8 years@noev in OkHttp 3.x you can use builder pattern (see github.com/square/okhttp/wiki/Interceptors) to add interceptors.
-
Weekend almost 8 years@zeeshan The solution in "EDIT #2" is dirty. According to doc of
NetworkPolicy.OFFLINE
, "Forces the request through the disk cache only, skipping network", that's the problem. (But it's only a guess. I haven't write a test demo.) -
Sanket Berde almost 8 years@Weekend hence the next request with no
NetworkPolicy.OFFLINE
in theonError()
of the first call. -
Billda over 7 yearsPlease be aware of
new OkHttpDownloader(this,Integer.MAX_VALUE)
part. This will set maximum size of cache to "infinity" and your app size will be increasing. -
VKostenc over 7 yearsWith
okhttp3.OkHttpClient
library you have to useOkHttp3Downloader
class formcompile 'com.jakewharton.picasso:picasso2-okhttp3-downloader:1.1.0'
-
Ali Ahmed about 7 yearsjava.lang.NoClassDefFoundError: Failed resolution of: Lcom/squareup/okhttp/OkHttpClient;
-
Mete over 6 yearsWith current versions, i give "Failed resolution of: Lcom/squareup/okhttp/OkHttpClient;" exception. But it works great when I use the versions you wrote.
-
Prakash over 6 years@Billda No it will not set cache to infinite. That value will be used to set the size limit for cache.
-
user25 about 6 yearscache isn't working, I even checked private app folder and
/cache/picasso-cache
folder is empty. I'm trying to cache thumbnails stackoverflow.com/a/30045646/4548520 -
user25 about 6 yearsit's not available anymore (
.with
), from 2.7 version -
ahmed hamdy about 6 years@user25 Ok, But I didn't use
with
method into my solution -
user924 about 6 years
OkHttp
is already inside picasso why should we put it in gradle? -
user924 about 6 years
Picasso.with(getActivity()) .load(imageUrl) .networkPolicy(NetworkPolicy.OFFLINE)
i don't see any picasso cache in app private folder -
user924 about 6 yearsnothing works, I see annoying placeholder all the time, github.com/square/picasso/issues/1936
-
user924 about 6 yearsyour solution has issues
Do not place Android context classes in static fields (static reference to Picasso which has field context pointing to Context); this is a memory leak (and also breaks Instant Run)
-
user924 about 6 yearsand remove unnecessary lines like
picasso.setIndicatorsEnabled(true); picasso.setLoggingEnabled(true);
it's for debug, it's not related to a question! -
Alexander Farber almost 6 yearsGlide is 5x more code than Picasso. When already using okhttp, better to use Picasso
-
Orri over 5 yearsBoth libraries use caching but cache differently: medium.com/@multidots/glide-vs-picasso-930eed42b81d
-
A1m about 5 yearsThis solution (Edit #2) works for me, but I am kinda confused how this is the proper solution to this problem. Is this really what Picasso suggests you to do when you want to have full offline support?
-
Arpit Anand over 3 yearsPicasso's version has changed and needed an update. I have suggested an edit! Great answer though. It worked for me after doing some changing.
-
Abhinav Chauhan over 3 years@ArpitAnand thanks, feel free to improve the answer , I shall accept the changes