3

I have a problem of out of memory due to limited virtual memory heap size.
Here is my code for fetching bitmap from server:

@SuppressWarnings("unchecked")
public class DrawableManager {

@SuppressWarnings("rawtypes")
private final Map drawableMap;

    @SuppressWarnings("rawtypes")
    private DrawableManager() {
        drawableMap = new HashMap();
    }

    static private DrawableManager  _instance;

    static public DrawableManager getInstance() {
        if(_instance == null) {
            _instance = new DrawableManager();
        }
        return _instance;
    }

    public Bitmap fetchBitmap(final String sURL) {
        if(sURL.length() == 0)
            return null;
        Bitmap bm = (Bitmap) drawableMap.get(sURL);
        if(bm != null) {
            return bm;
        }

        byte[] imageData = ThumbImg(sURL);

        if(imageData == null)
            return null;

        if(imageData.length > 0) {
            bm =  BitmapFactory.decodeByteArray(imageData, 0, imageData.length);
            if(bm != null) {
                drawableMap.put(sURL, bm);
            }
            return bm;
        }
        else { 
            return null;
        }
    }

    public void fetchBitmapOnThread(final String sURL, final ImageView imageView) {
        if (drawableMap.containsKey(sURL)) {
            imageView.setImageBitmap((Bitmap) drawableMap.get(sURL));
        }

        final Handler handler = new Handler() {
            @Override
            public void handleMessage(Message message) {
                imageView.setImageBitmap((Bitmap) message.obj);
            }
        };

        Thread thread = new Thread() {
            @Override
            public void run() {
                Bitmap bitmap = fetchBitmap(sURL);
                Message message = handler.obtainMessage(1, bitmap);
                handler.sendMessage(message);
            }
        };
        thread.start();
    }


    @SuppressWarnings("unused")
    public static byte[] ThumbImg(String imgUrl) 
    {

        //first check in the cache, if not available then store in the sd card memory
            HttpURLConnection connection = null;
            String userAgent = null;

            try
            {
                URL url = new URL(imgUrl);
                connection = ( HttpURLConnection ) url.openConnection();
                 if(userAgent != null) {
                     connection.setRequestProperty("User-Agent", userAgent);
                 }
                 connection.setConnectTimeout(5000);
                 connection.setReadTimeout(5000);
                    int CHUNKSIZE = 8192;        //size of fixed chunks
                int BUFFERSIZE = 1024;       //size of reading buffer


                 int bytesRead = 0;
                 byte[] buffer = new byte[BUFFERSIZE];   //initialize buffer
                 byte[] fixedChunk = new byte[CHUNKSIZE]; //initialize 1st chunk
                 ArrayList<byte[]> BufferChunkList = new ArrayList<byte[]>(); // List of chunk data
                 int spaceLeft = CHUNKSIZE;
                 int chunkIndex = 0;

                 DataInputStream in = new DataInputStream(connection.getInputStream() );

                 while( ( bytesRead = in.read( buffer ) ) != -1 ) { //loop until the DataInputStream is completed
                     if(bytesRead > spaceLeft) {
                         //copy to end of current chunk
                         System.arraycopy(buffer, 0, fixedChunk, chunkIndex, spaceLeft);
                         BufferChunkList.add(fixedChunk);

                         //create a new chunk, and fill in the leftover
                         fixedChunk = new byte[CHUNKSIZE];
                         chunkIndex = bytesRead - spaceLeft;
                         System.arraycopy(buffer, spaceLeft, fixedChunk, 0, chunkIndex);
                     } else {
                         //plenty of space, just copy it in
                         System.arraycopy(buffer, 0, fixedChunk, chunkIndex, bytesRead);
                         chunkIndex = chunkIndex + bytesRead;
                     }
                     spaceLeft = CHUNKSIZE - chunkIndex;
                 }

                 if (in != null) {
                     in.close();
                 }

                 // copy it all into one big array
                 int responseSize = (BufferChunkList.size() * CHUNKSIZE) + chunkIndex;  
                 Log.d("response size",""+responseSize);
                 byte[] responseBody = new byte[responseSize];
                 int index = 0;
                 for(byte[] b : BufferChunkList) {
                     System.arraycopy(b, 0, responseBody, index, CHUNKSIZE);
                     index = index + CHUNKSIZE;
                 }
                 System.arraycopy(fixedChunk, 0, responseBody, index, chunkIndex);

                return responseBody;                     


            }catch(SocketTimeoutException se)
            {

            }
            catch(Exception e)
            {

                e.printStackTrace();
            }finally
            {
                if(connection!=null)
                connection.disconnect();
            }

        return null;
    }

}

This is the code that I am using, this works fine with smaller images but not for large images. What is the problem and to solve it?

Thanks

0

2 Answers 2

6

Its not always a good idea to store bitmaps in memory. If you really want to do so then try using SoftReference for your map. Check this

make your map's value argument as SoftReference<Bitmap>. Then while searching in the map use this code snippet

@SuppressWarnings("unchecked")
public class DrawableManager {

@SuppressWarnings("rawtypes")
private final Map<String, SoftReference<Bitmap>> drawableMap;

    @SuppressWarnings("rawtypes")
    private DrawableManager() {
        drawableMap = new HashMap<String, SoftReference<Bitmap>>();
    }

    static private DrawableManager  _instance;

    static public DrawableManager getInstance() {
        if(_instance == null) {
            _instance = new DrawableManager();
        }
        return _instance;
    }

    public Bitmap fetchBitmap(final String sURL) {
        if(sURL.length() == 0)
            return null;
        Bitmap bm = null;
            SoftReference<Bitmap> reference = drawbaleM.get(imagePath);                  
            if(reference != null) bm = reference.get();
            if(bm != null) {
             return bm;
            }

        byte[] imageData = ThumbImg(sURL);

        if(imageData == null)
            return null;

        if(imageData.length > 0) {
            bm =  BitmapFactory.decodeByteArray(imageData, 0, imageData.length);
            if(bm != null) {
                drawableMap.put(sURL, bm);
            }
            return bm;
        }
        else { 
            return null;
        }
    }

    public void fetchBitmapOnThread(final String sURL, final ImageView imageView) {
        if (drawableMap.containsKey(sURL)) {
            imageView.setImageBitmap((Bitmap) drawableMap.get(sURL));
        }

        final Handler handler = new Handler() {
            @Override
            public void handleMessage(Message message) {
                imageView.setImageBitmap((Bitmap) message.obj);
            }
        };

        Thread thread = new Thread() {
            @Override
            public void run() {
                Bitmap bitmap = fetchBitmap(sURL);
                Message message = handler.obtainMessage(1, bitmap);
                handler.sendMessage(message);
            }
        };
        thread.start();
    }


    @SuppressWarnings("unused")
    public static byte[] ThumbImg(String imgUrl) 
    {

        //first check in the cache, if not available then store in the sd card memory
            HttpURLConnection connection = null;
            String userAgent = null;

            try
            {
                URL url = new URL(imgUrl);
                connection = ( HttpURLConnection ) url.openConnection();
                 if(userAgent != null) {
                     connection.setRequestProperty("User-Agent", userAgent);
                 }
                 connection.setConnectTimeout(5000);
                 connection.setReadTimeout(5000);
                    int CHUNKSIZE = 8192;        //size of fixed chunks
                int BUFFERSIZE = 1024;       //size of reading buffer


                 int bytesRead = 0;
                 byte[] buffer = new byte[BUFFERSIZE];   //initialize buffer
                 byte[] fixedChunk = new byte[CHUNKSIZE]; //initialize 1st chunk
                 ArrayList<byte[]> BufferChunkList = new ArrayList<byte[]>(); // List of chunk data
                 int spaceLeft = CHUNKSIZE;
                 int chunkIndex = 0;

                 DataInputStream in = new DataInputStream(connection.getInputStream() );

                 while( ( bytesRead = in.read( buffer ) ) != -1 ) { //loop until the DataInputStream is completed
                     if(bytesRead > spaceLeft) {
                         //copy to end of current chunk
                         System.arraycopy(buffer, 0, fixedChunk, chunkIndex, spaceLeft);
                         BufferChunkList.add(fixedChunk);

                         //create a new chunk, and fill in the leftover
                         fixedChunk = new byte[CHUNKSIZE];
                         chunkIndex = bytesRead - spaceLeft;
                         System.arraycopy(buffer, spaceLeft, fixedChunk, 0, chunkIndex);
                     } else {
                         //plenty of space, just copy it in
                         System.arraycopy(buffer, 0, fixedChunk, chunkIndex, bytesRead);
                         chunkIndex = chunkIndex + bytesRead;
                     }
                     spaceLeft = CHUNKSIZE - chunkIndex;
                 }

                 if (in != null) {
                     in.close();
                 }

                 // copy it all into one big array
                 int responseSize = (BufferChunkList.size() * CHUNKSIZE) + chunkIndex;  
                 Log.d("response size",""+responseSize);
                 byte[] responseBody = new byte[responseSize];
                 int index = 0;
                 for(byte[] b : BufferChunkList) {
                     System.arraycopy(b, 0, responseBody, index, CHUNKSIZE);
                     index = index + CHUNKSIZE;
                 }
                 System.arraycopy(fixedChunk, 0, responseBody, index, chunkIndex);

                return responseBody;                     


            }catch(SocketTimeoutException se)
            {

            }
            catch(Exception e)
            {

                e.printStackTrace();
            }finally
            {
                if(connection!=null)
                connection.disconnect();
            }

        return null;
    }

}

Please note this doesnot guarantee relief from OOM. It is not always a good idea to show large bitmaps.

Another option you can go after is use BitmapFactory.Options inSampleSize argument

Sign up to request clarification or add additional context in comments.

16 Comments

@frieza: but where and how to use SoftReferences in my code. Can you please explain
@frieza: Can you please edit your sample code in mine code as this is giving error on my side while making changes according your sample code
@frieza: But it is showing error in drawbleM.get() as not able to cast in sofwarereferense
As I have also used this as : private DrawableManager() { drawableMap = new HashMap(); } where DrawableManager is class and calling constructor
Sorry but what you are saying is not clear. Can you post your code
|
0

BitmapFactory.decodeByteArray() creates the bitmap data in the Native heap, not the VM heap. See BitmapFactory OOM driving me nuts for details.

You could monitor the Native heap (as per BitmapFactory OOM driving me nuts) and downsample if you're running short of space.

2 Comments

Can you please tell me where and how to include this sample in my code (as shown above) to run
Based on the SO response linked, since Honeycomb Bitmap are allocated on the VM heap. So this is not a solution anymore if your minSDK is more than 13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.