Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
172 views
in Technique[技术] by (71.8m points)

android - Out of memory exception due to large bitmap size

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

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...