0

hey guys having a problem after reloading an activity multiple times i get an out of memory exception and crashes out of the app i am using the developer google documentation example to load multiple images from what i see i have to recycle the bitmap once i am done with it but i am a bit unsure where to do this considering i have multiple bitmaps and calling the bitmap from an external class

Here is my load bitmap class

public class bitmapHTTP{

Context ctx;
private LruCache<String, Bitmap> mMemoryCache;
int iv;

public  bitmapHTTP(Context c){
    ctx = c;
    final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
    final int cacheSize = maxMemory / 8;

    mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {
        @Override
        protected int sizeOf(String key, Bitmap bitmap) {
            // The cache size will be measured in kilobytes rather than
            // number of items.
            return bitmap.getByteCount() / 1024;
        }
    };

}

public void addBitmapToMemoryCache(String key, Bitmap bitmap) {
    if(getBitmapFromMemCache(key) == null) {
        mMemoryCache.put(key, bitmap);
    }
}

public Bitmap getBitmapFromMemCache(String key) {
    return mMemoryCache.get(key);
}

public void loadBitmap(String resId, ImageView imageView) {
    final String imageKey = String.valueOf(resId);
    iv = imageView.getWidth();
    Bitmap bitmap = getBitmapFromMemCache(imageKey);
    if(bitmap != null) {
        imageView.setImageBitmap(bitmap);
    }else{
        if(cancelPotentialWork(imageKey, imageView)){
            Bitmap loading = decodeSampledBitmapFromResource(ctx.getResources(), R.drawable.whiteseetrough, imageView.getWidth(), imageView.getWidth());
            BitmapWorkerTask task = new BitmapWorkerTask(imageView);
            AsyncDrawable asyncDrawable = new AsyncDrawable(ctx.getResources(), loading, task);
            imageView.setImageDrawable(asyncDrawable);
            task.execute(resId);
        }
    }
}

public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
    // Raw height and width of image
    final int height = options.outHeight;
    final int width = options.outWidth;
    int inSampleSize = 1;

    if (height > reqHeight || width > reqWidth) {

        final int halfHeight = height / 2;
        final int halfWidth = width / 2;

        // Calculate the largest inSampleSize value that is a power of 2 and keeps both
        // height and width larger than the requested height and width.
        while ((halfHeight / inSampleSize) > reqHeight
                && (halfWidth / inSampleSize) > reqWidth) {
            inSampleSize *= 2;
        }
    }

    return inSampleSize;
}

public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId, int reqWidth, int reqHeight) {

    // First decode with inJustDecodeBounds=true to check dimensions
    final BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeResource(res, resId, options);

    // Calculate inSampleSize
    options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

    // Decode bitmap with inSampleSize set
    options.inJustDecodeBounds = false;
    return BitmapFactory.decodeResource(res, resId, options);
}

class BitmapWorkerTask extends AsyncTask<String, Void, Bitmap> {
    private final WeakReference<ImageView> imageViewReference;
    private String data = null;

    public BitmapWorkerTask(ImageView imageView) {
        // Use a WeakReference to ensure the ImageView can be garbage collected
        imageViewReference = new WeakReference<ImageView>(imageView);
    }

    // Decode image in background.
    @Override
    protected Bitmap doInBackground(String... params) {
        data = params[0];
        final BitmapFactory.Options options = new BitmapFactory.Options();
        Bitmap bitmap;

        if(data.equals("null")){
            bitmap = decodeSampledBitmapFromResource(ctx.getResources(), R.drawable.whiteseetrough, iv, iv);
            addBitmapToMemoryCache(String.valueOf(params[0]), bitmap);
            return bitmap;
        }else{
            bitmap = getBitmapFromMemCache(data);
            if(bitmap == null){
                // Process as normal
                try {
                    URL url = new URL(data);
                    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                    connection.setDoInput(true);
                    connection.connect();
                    InputStream input = connection.getInputStream();

                    options.inSampleSize = calculateInSampleSize(options, iv, iv);

                    options.inJustDecodeBounds = false;
                    bitmap = BitmapFactory.decodeStream(input, null, options);
                    addBitmapToMemoryCache(String.valueOf(params[0]), bitmap);
                    return bitmap;

                }catch(IOException e){
                    e.printStackTrace();
                    return null;
                }
            }

        }
        return bitmap;
    }

    // Once complete, see if ImageView is still around and set bitmap.

    @Override
    protected void onPostExecute(Bitmap bitmap) {
        if (isCancelled()) {
            bitmap = null;
        }

        if (imageViewReference != null && bitmap != null) {
            final ImageView imageView = imageViewReference.get();
            final BitmapWorkerTask bitmapWorkerTask =
                    getBitmapWorkerTask(imageView);
            if (this == bitmapWorkerTask && imageView != null) {
                imageView.setImageBitmap(bitmap);
            }
        }
    }

}

static class AsyncDrawable extends BitmapDrawable {
    private final WeakReference<BitmapWorkerTask> bitmapWorkerTaskReference;

    public AsyncDrawable(Resources res, Bitmap bitmap,
                         BitmapWorkerTask bitmapWorkerTask) {
        super(res, bitmap);
        bitmapWorkerTaskReference =
                new WeakReference<BitmapWorkerTask>(bitmapWorkerTask);
    }

    public BitmapWorkerTask getBitmapWorkerTask() {
        return bitmapWorkerTaskReference.get();
    }
}

public static boolean cancelPotentialWork(String data, ImageView imageView) {
    final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView);

    if (bitmapWorkerTask != null) {
        final String bitmapData = bitmapWorkerTask.data;
        // If bitmapData is not yet set or it differs from the new data
        if(bitmapData == null || bitmapData != data) {
            // Cancel previous task
            bitmapWorkerTask.cancel(true);
        } else {
            // The same work is already in progress
            return false;
        }
    }
    // No task associated with the ImageView, or an existing task was cancelled
    return true;
}

private static BitmapWorkerTask getBitmapWorkerTask(ImageView imageView) {
    if (imageView != null) {
        final Drawable drawable = imageView.getDrawable();
        if (drawable instanceof AsyncDrawable) {
            final AsyncDrawable asyncDrawable = (AsyncDrawable) drawable;
            return asyncDrawable.getBitmapWorkerTask();
        }
    }
    return null;
}

}

this is how i call the bitmap to load to an imageView

bitmapHTTP getBitmap = new bitmapHTTP(this);

    getBitmap.loadBitmap(imageUrl, 1), imageView1);
    getBitmap.loadBitmap(imageUrl, 1), imageView2);
    getBitmap.loadBitmap(imageUrl, 1), imageView3);
user2692997
  • 2,001
  • 2
  • 14
  • 20
  • I think, there is a memory leak somewhere – Vyacheslav Dec 02 '16 at 19:04
  • please check this old answer of mine, it's still applies and still is very valid http://stackoverflow.com/questions/31162558/loading-images-in-a-gridview-from-server-android/31162942#31162942 – Budius Dec 02 '16 at 19:21

1 Answers1

0

Thats a lot of code. Quickly I would ask: Are you recycling your bitmaps after not needing them? Bitmaps need to be recycled and RAM released especially when loading them via loops and the like and keeping references to them.

Check your code to make sure you recycling properly. I didn't see anything of the kind (releasing the reference is not enough if you want to do a low of bitmaping).

Also, keep in mind that you need to make sure your bitmaps are loaded in properly in available memory and resized so that they don't kill the memory. I believe you are doing it somewhere in there.

George
  • 1,224
  • 12
  • 21
  • yes the images are been loaded properly my problem is am not too sure where i need to recycle them and how to recycle them from a my main class – user2692997 Dec 02 '16 at 21:01
  • Don't mean to offend your code but have a look here, it may help you move on to other tasks. https://github.com/square/picasso – George Dec 02 '16 at 21:04