由于位图大小较大而导致内存不足

时间:2011-03-16 05:55:44

标签: android

由于虚拟内存堆大小有限,我遇到了内存不足的问题 这是我从服务器获取位图的代码:

@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;
    }

}

这是我正在使用的代码,这适用于较小的图像,但不适用于大图像。有什么问题需要解决?

由于

2 个答案:

答案 0 :(得分:5)

将位图存储在内存中并不总是一个好主意。如果您确实想这样做,请尝试使用SoftReference作为地图。 Check this

将地图的值参数设为SoftReference<Bitmap>。然后在地图中搜索时使用此代码段

@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;
    }

}

请注意,这并不能保证从OOM中解脱出来。显示大位图并不总是一个好主意。

您可以使用的另一个选项是使用BitmapFactory.Options inSampleSize参数

答案 1 :(得分:0)

BitmapFactory.decodeByteArray()在Native堆中创建位图数据,而不是VM堆。有关详细信息,请参阅BitmapFactory OOM driving me nuts

您可以监控本机堆(根据BitmapFactory OOM driving me nuts),如果您的空间不足,则可以下采样。<​​/ p>