In my Android app, I am using a custom ImageView class (Banner) to display images pulled from Facebook Events. While running the app, I notice that there is a large heap size (120 MB) while running the app. I used MAT and I think I've narrowed it down to byte[]
and then finally to ImageView
. Please check the pictures below to see how I came to this conclusion.
Now, I've read similar posts and I tried recycling my bitmap, using WeakReferences, creating a cache, but nothing seems to be reducing the memory size. However, recycling my bitmap threw me an error which said that I can't use a recycled bitmap (I feel like that may be a hint because it's keeping my bitmap in memory?).
The app isn't running slowly on my phone (It even only says a CPU usage of 1.5% even though the memory is on average 100 MB). I will post my Banner subclass and how I download the images to see if anyone can help me.
Banner.java
:
public class Banner extends ImageView {
public Banner(Context context) {
super(context);
}
public Banner(Context context, AttributeSet attrs) {
super(context, attrs);
}
public Banner(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = 400;
if (getDrawable() != null && getDrawable().getIntrinsicWidth() != 0){
height = width * getDrawable().getIntrinsicHeight() / getDrawable().getIntrinsicWidth();
if (height < 500)
height = 700;
}
setMeasuredDimension(width, height);
setColorFilter(Color.rgb(123, 123, 123), android.graphics.PorterDuff.Mode.MULTIPLY);
}
public void onDestroy(){
Drawable drawable = this.getDrawable();
if (drawable instanceof BitmapDrawable) {
BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
Bitmap bitmap = bitmapDrawable.getBitmap();
bitmap.recycle();
}
this.setImageBitmap(null);
}
}
BannerLoader.java
:
public class BannerLoader{
private String url;
private WeakReference<ImageView> cover;
private LruCache<String, WeakReference<Bitmap>> mMemoryCache;
final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
final int cacheSize = maxMemory / 8;
public BannerLoader(String cover_url, WeakReference<ImageView> cover, Drawable defaultDrawable) {
this.url = cover_url;
this.cover = cover;
cover.get().setBackground(defaultDrawable);
mMemoryCache = new LruCache<String, WeakReference<Bitmap>>(cacheSize) {
@Override
protected int sizeOf(String key, WeakReference<Bitmap> bitmap) {
// The cache size will be measured in kilobytes rather than
// number of items.
return bitmap.get().getByteCount() / 1024;
}
};
new DownloadImage().execute();
}
public void addBitmapToMemoryCache(String key, WeakReference<Bitmap> bitmap) {
if (getBitmapFromMemCache(key) == null) {
mMemoryCache.put(key, bitmap);
}
}
public WeakReference<Bitmap> getBitmapFromMemCache(String key) {
return mMemoryCache.get(key);
}
class DownloadImage extends AsyncTask<Void, Void, WeakReference<Bitmap>>{
protected WeakReference<Bitmap> doInBackground(Void... params){
try {
final WeakReference<Bitmap> cachedBitmap = getBitmapFromMemCache(url);
if (cachedBitmap != null){
return cachedBitmap;
} else{
URL pictureURL = new URL(url);
HttpGet httpRequest = null;
httpRequest = new HttpGet(pictureURL.toURI());
HttpClient httpclient = new DefaultHttpClient();
HttpResponse response = (HttpResponse) httpclient
.execute(httpRequest);
HttpEntity entity = response.getEntity();
BufferedHttpEntity b_entity = new BufferedHttpEntity(entity);
InputStream input = b_entity.getContent();
WeakReference<Bitmap> bitmap = new WeakReference<Bitmap>(BitmapFactory.decodeStream(input));
addBitmapToMemoryCache(url, bitmap);
return bitmap;
}
} catch(Exception ex){
ex.printStackTrace();
}
return null;
}
public void onPostExecute(WeakReference<Bitmap> image){
if (image != null && cover.get() != null){
cover.get().setImageBitmap(image.get());
}
}
}
}
So, as an example, I download an image like this:
new BannerLoader(tempEvent.getCover_url(), new WeakReference<ImageView>(thumb_image), context.getResources().getDrawable(R.drawable.placeholder));
Thanks for the help!