2 baifaxiaoyao baifaxiaoyao 于 2012.09.14 11:11 提问

当向Bitmap对象加载图片时,出现奇怪内存不够问题。

我不确定从哪开始解释这个问题。
在每一行,我有一个带着一对图片按钮的列表视图。当你点击列表行,它加载一个新的控件。因为照相机布局的问题我不得不建立我新的tab。这个控件加载完成的结果是一个地图。如果我点击我的按钮来加载图片预览(从SD卡加载一个图片)应用程序从这个控件返回到列表视图控件,导致结果处理器重新加载我的新的控件,那个不过就是一个图像的小部件。
所以这就是问题,图片显示在列表视图的时候都是带着光标和列表转换器的。这使得它相当的简单,但是我不确定我怎么能够调整大小(IE下有一点小,但是不是像素的关心)图片作为图片按钮的源文件在起作用。所以我只是调整了来自于手机、相机的照片的大小。
这个问题就是当它试图返回重新加载第二个控件的时候出现了内存不足的问题。
我的问题:是否有方法让我可以逐行创建列表转换器,那样我可以调整在运行中的图片的大小(按位)?这将是合适的,因为我还需要给每一行的小工具/元素做一些属性的改变,为了我不能在触摸屏的编辑选择有焦点的一行(我可以使用滚动条)。
我知道我可以做一个不同频道信号传输来改变图片大小,并保存我的图片,但是这真的不是我想要做的,但是如果你能够给一些建议的示例代码那将是很好的。
我是这样做的

    String[] from = new String[] { DBHelper.KEY_BUSINESSNAME, DBHelper.KEY_ADDRESS, DBHelper.KEY_CITY, DBHelper.KEY_GPSLONG, DBHelper.KEY_GPSLAT,  DBHelper.KEY_IMAGEFILENAME  + ""};
        to = new int[] { R.id.businessname, R.id.address, R.id.city, R.id.gpslong, R.id.gpslat, R.id.imagefilename };
         notes =
            new SimpleCursorAdapter(this, R.layout.notes_row, c, from, to);
        setListAdapter(notes);
Where R.id.imagefilename is a ButtonImage

R.id.imagefilename是一个按钮图片
这是我的日志

09-13 05:05:49.877: ERROR/dalvikvm-heap(3896): 6291456-byte external allocation too large for this process.
09-13 05:05:49.877: ERROR/(3896): VM wont let us allocate 6291456 bytes
09-13 05:05:49.877: ERROR/AndroidRuntime(3896): Uncaught handler: thread main exiting due to uncaught exception
09-13 05:05:49.917: ERROR/AndroidRuntime(3896): java.lang.OutOfMemoryError: bitmap size exceeds VM budget
09-13 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.graphics.BitmapFactory.nativeDecodeStream(Native Method)
09-13 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:304)
09-13 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:149)
09-13 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:174)
09-13 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.graphics.drawable.Drawable.createFromPath(Drawable.java:729)
09-13 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.ImageView.resolveUri(ImageView.java:484)
09-13 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.ImageView.setImageURI(ImageView.java:281)
09-13 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.SimpleCursorAdapter.setViewImage(SimpleCursorAdapter.java:183)
09-13 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.SimpleCursorAdapter.bindView(SimpleCursorAdapter.java:129)
09-13 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.CursorAdapter.getView(CursorAdapter.java:150)
09-13 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.AbsListView.obtainView(AbsListView.java:1057)
09-13 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.ListView.makeAndAddView(ListView.java:1616)
09-13 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.ListView.fillSpecific(ListView.java:1177)
09-13 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.ListView.layoutChildren(ListView.java:1454)
09-13 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.AbsListView.onLayout(AbsListView.java:937)
09-13 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.view.View.layout(View.java:5611)
09-13 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1119)
09-13 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.LinearLayout.layoutHorizontal(LinearLayout.java:1108)
09-13 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.LinearLayout.onLayout(LinearLayout.java:922)
09-13 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.view.View.layout(View.java:5611)
09-13 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.FrameLayout.onLayout(FrameLayout.java:294)
09-13 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.view.View.layout(View.java:5611)
09-13 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1119)
09-13 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.LinearLayout.layoutVertical(LinearLayout.java:999)
09-13 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.LinearLayout.onLayout(LinearLayout.java:920)
09-13 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.view.View.layout(View.java:5611)
09-13 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.FrameLayout.onLayout(FrameLayout.java:294)
09-13 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.view.View.layout(View.java:5611)
09-13 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.view.ViewRoot.performTraversals(ViewRoot.java:771)
09-13 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.view.ViewRoot.handleMessage(ViewRoot.java:1103)
09-13 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.os.Handler.dispatchMessage(Handler.java:88)
09-13 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.os.Looper.loop(Looper.java:123)
09-13 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.app.ActivityThread.main(ActivityThread.java:3742)
09-13 05:05:49.917: ERROR/AndroidRuntime(3896):     at java.lang.reflect.Method.invokeNative(Native Method)
09-13 05:05:49.917: ERROR/AndroidRuntime(3896):     at java.lang.reflect.Method.invoke(Method.java:515)
09-13 05:05:49.917: ERROR/AndroidRuntime(3896):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:739)
09-13 05:05:49.917: ERROR/AndroidRuntime(3896):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:497)
09-13 05:05:49.917: ERROR/AndroidRuntime(3896):     at dalvik.system.NativeStart.main(Native Method)
09-13 05:10:01.127: ERROR/AndroidRuntime(3943): ERROR: thread attach failed

当显示一个图片的时候我又有了一个新问题

09-13 22:13:18.594: DEBUG/skia(4204): xxxxxxxxxxx jpeg error 20 Improper call to JPEG library in state %d
09-13 22:13:18.604: INFO/System.out(4204): resolveUri failed on bad bitmap uri: 
09-13 22:13:18.694: ERROR/dalvikvm-heap(4204): 6291456-byte external allocation too large for this process.
09-13 22:13:18.694: ERROR/(4204): VM won't let us allocate 6291456 bytes
09-13 22:13:18.694: DEBUG/skia(4204): xxxxxxxxxxxxxxxxxxxx allocPixelRef failed

7个回答

mansuifengqi
mansuifengqi   2012.09.14 11:36
已采纳

当加载位图时,Android Training类,“Displaying Bitmaps Efficiently”,提供一些多的信息来理解和处理这个异常java.lang.OutOfMemoryError: bitmap size exceeds VM budget

yizhenbeifeng
yizhenbeifeng   2012.09.14 13:23

我遇到了同样的问题,通过规避BitmapFactory.decodeStream或者decodeFile函数,使用BitmapFactory.decodeFileDescriptor解决的
decodeFileDescriptor相比decodeStream/decodeFile来说,看起来它调用了不同的本地方法。
无论如何,它是这样工作的(注意,像上边的一样,我增加了一些设置,但那不是使这个不同的地方。)关键的就是它调用Bitmap.decodeFileDescriptor而不是decodeStream or decodeFile)。

private void showImage(String path)   {
    Log.i("showImage","loading:"+path);
    BitmapFactory.Options bfOptions=new BitmapFactory.Options();
    bfOptions.inDither=false;                     
    bfOptions.inPurgeable=true;                 
    bfOptions.inInputShareable=true;             
    bfOptions.inTempStorage=new byte[32 * 1024]; 


    File file=new File(path);
    FileInputStream fs=null;
    try {
        fs = new FileInputStream(file);
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    }

    try {
        if(fs!=null) bm=BitmapFactory.decodeFileDescriptor(fs.getFD(), null, bfOptions);
    } catch (IOException e) {
        e.printStackTrace();
    } finally{ 
        if(fs!=null) {
            try {
                fs.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    im.setImageBitmap(bm);
    bm=null;
}

我想这可能是decodeStream/decodeFile中本地函数的问题。我很确定当使用decodeFileDescriptor时一个不同的本地方法被调用。我读到的也是“图片(Bitmaps)并不是指派给一个标准的java路径,但是是通过本地调用的;这个分配是在虚拟的堆外完成的,但是是被认为针对它的!”。

Sueyexin
Sueyexin   2012.09.14 11:50

为了修改内存不足的问题你应该像下边这样做:

BitmapFactory.Options options=new BitmapFactory.Options();
options.inSampleSize = 8;
Bitmap preview_bitmap=BitmapFactory.decodeStream(is,null,options);
This inSampleSize option reduces memory consumption.

inSampleSize这个选项可以减少内存消耗。
这是一个彻底的解决方法。首先,它读取这个文件的大小,但是不用解码这个目录本身。然后,它发现最好的inSampleSize值,它需要大量的2.最后这个图片就可以被解码了。

//解码图片然后对图片进行缩放以减少内存消耗
private Bitmap decodeFile(File f){
    try {
        //解码图片大小
        BitmapFactory.Options o = new BitmapFactory.Options();
        o.inJustDecodeBounds = true;
        BitmapFactory.decodeStream(new FileInputStream(f),null,o);

        //我们想要的新的图片大小
        final int REQUIRED_SIZE=70;
        int scale=1;
        while(o.outWidth/scale/2>=REQUIRED_SIZE && o.outHeight/scale/2>=REQUIRED_SIZE)
            scale*=2;

        //用inSampleSize解码
        BitmapFactory.Options o2 = new BitmapFactory.Options();
        o2.inSampleSize=scale;
        return BitmapFactory.decodeStream(new FileInputStream(f), null, o2);
    } catch (FileNotFoundException e) {}
    return null;
}
suannai0314
suannai0314 我认为,10可能是inSampleSize 最好的值,但是证明文件建议使用2
大约 5 年之前 回复
gouxiaojin
gouxiaojin   2012.09.14 13:15

我给第二个答案的代码做了一些改进。它的基本原理是一样的,但是它没有令人讨厌的循环(个人观点),它的结果仍然是许多的2.第二个答案给出了根本的解决方法,当我发现的时候我被震撼住了,然后我才能给出下边的答案。

private Bitmap decodeFile(File f){
    Bitmap b = null;
    try {
        BitmapFactory.Options o = new BitmapFactory.Options();
        o.inJustDecodeBounds = true;

        FileInputStream fis = new FileInputStream(f);
        BitmapFactory.decodeStream(fis, null, o);
        fis.close();

        int scale = 1;
        if (o.outHeight > IMAGE_MAX_SIZE || o.outWidth > IMAGE_MAX_SIZE) {
            scale = (int)Math.pow(2, (int) Math.round(Math.log(IMAGE_MAX_SIZE / (double) Math.max(o.outHeight, o.outWidth)) / Math.log(0.5)));
        }

        BitmapFactory.Options o2 = new BitmapFactory.Options();
        o2.inSampleSize = scale;
        fis = new FileInputStream(f);
        b = BitmapFactory.decodeStream(fis, null, o2);
        fis.close();
    } catch (IOException e) {
    }
    return b;
}
qishizhishihuanjue
qishizhishihuanjue   2014.02.14 15:08

IMAGE_MAX_SIZE 应该赋多少?

duantihi
duantihi   2016.01.13 14:04

mark!! bitmap内存占用及优化亲测:http://blog.csdn.net/duantihi/article/details/50492056

u1254z62
u1254z62   2017.01.03 18:17

mark!! bitmap内存占用及优化亲测:http://blog.csdn.net/duantihi/article/details/50492056

Csdn user default icon
上传中...
上传图片
插入图片
准确详细的回答,更有利于被提问者采纳,从而获得C币。复制、灌水、广告等回答会被删除,是时候展现真正的技术了!