Reputation: 385
I'm using picasso to load images from server in my list adapter. When I'm scrolling list up and down Picasso keeps allocate more and more memory, screen below:
Here is part of my list adapter:
@Override
public View getView(final int position, View convertView, ViewGroup viewGroup) {
ViewHolder viewHolder;
if (convertView == null || convertView.getTag() == null) {
//init list item
viewHolder = new ViewHolder();
LayoutInflater inflater = (LayoutInflater) mContext
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.subfood_item, viewGroup,
false);
viewHolder.mImgvPicture = (ImageView) convertView.findViewById(R.id.imgvPicture);
viewHolder.mTvHeader = (TextView) convertView.findViewById(R.id.tvHeader);
viewHolder.mTvDescription = (TextView) convertView.findViewById(R.id.tvDescription);
convertView.setTag(viewHolder);
} else {
//list item is used again - get all references for view
viewHolder = (ViewHolder) convertView.getTag();
}
Product product = mItems.get(position);
viewHolder.mTvHeader.setText(product.getName());
viewHolder.mTvDescription.setText(product.getDescription());
if (product.isAsset()) {
String folderPath = "file:///android_asset/product/";
Picasso.with(mContext).load(folderPath + product.getPath()).fit().centerCrop().
into(viewHolder.mImgvPicture);
} else {
RestUtils.loadImageWithPicasso(RestUtils.URL_IMAGE_FROM_PRODUCT + product.getNetId(), viewHolder.mImgvPicture);
}
return convertView;
}
First part - loading from assets is fine. Problem is with:
RestUtils.loadImageWithPicasso(RestUtils.URL_IMAGE_FROM_PRODUCT + product.getNetId(), viewHolder.mImgvPicture);
I've wrapped this with additional method because of server authentication and offline caching. Below is code of RestUtils.loadImageWithPicasso
public static void loadImageWithPicasso(String url, ImageView imageView) {
float dp = App.getContext().getResources().getDisplayMetrics().density;
if(dp<=4.0f){
url = url+"?size="+(int)Math.floor(dp);
} else {
url = url+"?size=4";
}
String requestUrl = RestUtils.getUrl(url);
OkHttpClient picassoClient = new OkHttpClient();
final String finalUrl = url;
String hash = RestUtils.getHashed(finalUrl);
Interceptor interceptor = new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request newRequest = chain.request().newBuilder()
.addHeader(RestUtils.HEADER, RestUtils.getHashed(finalUrl))
.build();
return chain.proceed(newRequest);
}
};
picassoClient.interceptors().add(interceptor);
File httpCacheDir = new File(App.getContext().getExternalCacheDir(), RestUtils.IMAGE_CACHE);
long httpCacheSize = 40 * 1024 * 1024;
Cache cache = new Cache(httpCacheDir, httpCacheSize);
picassoClient.setCache(cache);
Picasso picasso = new Picasso.Builder(App.getContext()).downloader(new OkHttpDownloader(picassoClient)).build();
picasso.load(requestUrl)
.into(imageView);
}
Even if I quit from fragment, memory is still allocated.
Upvotes: 0
Views: 625
Reputation: 32026
Not sure you can blame picasso on this one. You are building a custom Picasso
instance with a new cache on every image load. Every time you call loadImageWithPicasso
, your code is allocating at least the following new objects -OkHttpClient
, Interceptor
, File
, Cache
, Picasso
and at least two String
's. You should only be building your Picasso
instance once.
There are a couple ways you choose to do that. One is -
Divide loadImageWithPicasso
into two methods createCustomPicasso
that returns your custom picasso object, call that once in your UI code and save in a member variable.
Then, modify loadImageWithPicasso
so that it takes a picasso instance you can pass in --
public static void loadImageWithPicasso(Picasso picasso, String url, ImageView imageView)
and then have it do the url-specific modifications before issuing the requests.
As a last note, your Interceptor
should be getting the data it needs to modify the request out of chain.getRequest()
instead of using data from outside its immediate scope. You are referencing finalUrl
inside your interceptor. It like can be replaced with chain.getRequest().urlString()
See the documentation on interceptors for a good walk through on the usage.
Upvotes: 2