I have a simple ListActivity that shows images and I inizialize my OkHttpClient for Picasso Builder in the constructor of the ImageAdapter class:
picassoClient = new OkHttpClient();
picassoClient.interceptors().add(new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request newRequest = chain
.request()
.newBuilder()
.addHeader("Cookie","xyz")
.build();
return chain.proceed(newRequest);
}
});
new Picasso.Builder(context).downloader(new OkHttpDownloader(picassoClient)).build();
then in getView()
I use Picasso to load images in ImageView:
Picasso.with(context).load(xyzUrl).fit().centerCrop().into(vImage);
It works well, but on device's rotation i see that heap size sometimes slowly grows, sometimes quickly and sometimes remains stable. Only rarely it drops. Am i leaking memory or is there something wrong in code?
EDIT:
I inserted this code after Picasso's call in the getView()
if (BuildConfig.DEBUG) {
Log.i("HEAP SIZE",
String.valueOf((Runtime.getRuntime().totalMemory() / 1024)
- (Runtime.getRuntime().freeMemory() / 1024)));
}
and I found that the heap size's growth happens in the getView()
after loading bitmap into ImageView.
What is wrong?
EDIT 2: tried to set static ImageAdapter, nothing changes
EDIT 3:
tried with RecyclerView instead of ListView, same behavior: heap size grows continuously while scrolling image list stepping by 30-40 bytes at every onBindViewHolder()
. After device's rotation heap size grows sometimes stepping by even 2-3 Mbytes. Rarely it drops.
Why heap size slowly but continuously grows and why am I leaking some cache or some cached bitmaps after device's rotation?
UPDATE:
tried adapter without the code in the constructor (that is without new OkHttpClient
and new Picasso.Builder
), it works and the heap size now drops well remaining stable. Then, what is the correct way to initialize the client with cookies headers management?
UPSHOT: finally I created my PicassoInstance class, which creates a unique static Picasso singleton and set it as the Picasso Library's singleton. Then I set it in my adapter constructor
PicassoInstance.setPicassoSingleton(context);
It works well, and it is a correct way I hope.
public class PicassoInstance {
private static Picasso myPicassoInstance = null;
public static void setPicassoSingleton(Context context) {
if (myPicassoInstance == null) {
myPicassoInstance = createMyPicassoInstance(context);
Picasso.setSingletonInstance(myPicassoInstance);
if (BuildConfig.DEBUG) {
Log.i("PICASSO INSTANCE", "CREATED");
}
}
}
private static Picasso createMyPicassoInstance(Context context) {
OkHttpClient myOkHttpClient = new OkHttpClient();
myOkHttpClient.interceptors().add(new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request newRequest = chain.request().newBuilder()
.addHeader("Cookie", "xyz").build();
if (BuildConfig.DEBUG) {
Log.i("ON INTERCEPT", "COOKIE ADDED");
}
return chain.proceed(newRequest);
}
});
return new Picasso.Builder(context).downloader(
new OkHttpDownloader(myOkHttpClient)).build();
}
}
The picasso instance being returned from PicassoBuilder.build() should be a singleton, and when you need to use picasso throughout the app you should be accessing that singleton, instead of Picasso.with... you should be accessing
YourClass.getMyPicassoSingleton().with...
Otherwise you're keeping separate caches, etc for those picasso instances
edit: as I noted below, you can also call
picasso.setSingletonInstance(myPicasso);
right where you invoke the build method above, which would also solve your problem without holding onto the singleton yourself. that is probably a cleaner solution
I cannot close it as too broad, but I'd recommend you took a memory dump and gave it a long hard look in Eclipse Memory Analizer Tool to find which references are still being kept alive and by who.
This is also a great write up on it.
Adapters as fields are leaky. Views contain context which contains views. And fragments are even worse offenders. ListActivities were an API1 tool that should have been deprecated long ago. All very leak prone, but that's the Android way.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With