内存不足异常CreateBitmap

时间:2015-09-01 01:25:38

标签: android memory bitmap

我目前正在开发我的第一个Android应用程序,它涉及用户能够在其库存中获取武器。这些武器从抽屉中随机拼接在一起(刀柄+刀片+手柄......等)。清单是一个带有自定义ArrayAdapter的gridview,用于显示武器图标。

问题是我在生成15个武器时会得到一个OutOfMemoryException。我的目标是让Inventory能够支持数百个项目。从日志中,我能够看到问题所在: Bitmap result = Bitmap.createBitmap(woh300, woh300, Bitmap.Config.ARGB_8888);我使位图如此之大的原因是因为我让用户能够点击清单中的武器图标,这会显示它们的放大图像。

以下是日志:

 java.lang.OutOfMemoryError: Failed to allocate a 1930512 byte allocation with 434524 free bytes and 424KB until OOM
            at dalvik.system.VMRuntime.newNonMovableArray(Native Method)
            at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method)
            at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:726)
            at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:547)
            at android.graphics.BitmapFactory.decodeResource(BitmapFactory.java:575)
            at android.graphics.BitmapFactory.decodeResource(BitmapFactory.java:605)
            at com.example.android.justdoit.Weapon.<init>(Weapon.java:31)
            at com.example.android.justdoit.UpdateInvTask.onPostExecute(UpdateInvTask.java:48)
            at com.example.android.justdoit.UpdateInvTask.onPostExecute(UpdateInvTask.java:17)
            at android.os.AsyncTask.finish(AsyncTask.java:632)
            at android.os.AsyncTask.access$600(AsyncTask.java:177)
            at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:645)
            at android.os.Handler.dispatchMessage(Handler.java:102)
            at android.os.Looper.loop(Looper.java:145)
            at android.app.ActivityThread.main(ActivityThread.java:5942)
            at java.lang.reflect.Method.invoke(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:372)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1399)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1194)

我的武器课程:

public class Weapon extends Equipment{
    public Weapon(Context context){
        //get the array of drawables located in the res/values/weapons.xml
        Resources res = context.getResources();
        TypedArray handles = res.obtainTypedArray(R.array.handles);
        TypedArray hilts = res.obtainTypedArray(R.array.hilts);
        TypedArray blades = res.obtainTypedArray(R.array.blades);
        TypedArray middles = res.obtainTypedArray(R.array.middles);
        TypedArray ends = res.obtainTypedArray(R.array.ends);
        //randomize the grip, hilt, blade
        Random rand = new Random();
        Bitmap handle = BitmapFactory.decodeResource(context.getResources(), handles.getResourceId(rand.nextInt(handles.length()), 0));
        Bitmap hilt = BitmapFactory.decodeResource(context.getResources(), hilts.getResourceId(rand.nextInt(hilts.length()), 0));
        Bitmap blade = BitmapFactory.decodeResource(context.getResources(), blades.getResourceId(rand.nextInt(blades.length()), 0));
        Bitmap end = BitmapFactory.decodeResource(context.getResources(), ends.getResourceId(rand.nextInt(ends.length()), 0));
        Bitmap middle = BitmapFactory.decodeResource(context.getResources(), middles.getResourceId(rand.nextInt(middles.length()), 0));

        Bitmap[] parts = new Bitmap[5];
        parts[0] = handle;
        parts[1] = hilt;
        parts[2] = blade;
        parts[3] = middle;
        parts[4] = end;

        int woh5 = Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 5, res.getDisplayMetrics()));
        int woh25 = Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 25, res.getDisplayMetrics()));
        int woh130 = Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 130, res.getDisplayMetrics()));
        int woh138= Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 138, res.getDisplayMetrics()));
        int woh162 = Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 162, res.getDisplayMetrics()));
        int woh170 = Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 170, res.getDisplayMetrics()));
        int woh172 = Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 172, res.getDisplayMetrics()));
        int woh258 = Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 258, res.getDisplayMetrics()));
        int woh300 = Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 300, res.getDisplayMetrics()));

        Bitmap result = Bitmap.createBitmap(woh300, woh300, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(result);
        Paint paint = new Paint();

        //rect is left, top, right, bottom
        //set the full image.  icon is a scaled-down version of the full image
        canvas.drawBitmap(parts[2], null, new Rect(woh5 * 25, woh5 * 6, woh5 * 35, woh5 * 37), paint);
        canvas.drawBitmap(parts[0], null, new Rect(woh138, woh5 * 37, woh162, woh5 * 52), paint);
        canvas.drawBitmap(parts[1], null, new Rect(woh25*3, woh172, woh25*9, woh5 * 42), paint);
        canvas.drawBitmap(parts[3], null, new Rect(woh130, woh172, woh170, woh5 * 42), paint);
        canvas.drawBitmap(parts[4], null, new Rect(woh138, woh258, woh162, woh5 * 57), paint);
        setFullImage(result);

        //recycle the typedarrays
        result = null;
        canvas = null;
        handles.recycle();
        hilts.recycle();
        blades.recycle();
        middles.recycle();
        ends.recycle();
    }
}

我一直在阅读Android开发人员指南的“管理位图内存”部分,但作为我的第一个应用程序,我知道我的位图创建可能已经过时了,我想我可以使用一些输入,如果我需要完全更改在尝试更好地管理内存之前,我会生成位图。谢谢。

1 个答案:

答案 0 :(得分:0)

请查看here

  

图像有各种形状和大小。在许多情况下,它们更大   比典型的应用程序用户界面(UI)所需。对于   例如,系统库应用程序显示使用的照片   您的Android设备的相机通常要高得多   分辨率高于设备的屏幕密度。

     

鉴于你正在使用有限的内存,理想情况下你只想要   在内存中加载较低分辨率的版本。分辨率较低   version应与显示它的UI组件的大小相匹配。一个   具有更高分辨率的图像不会提供任何明显的好处,   但仍占用宝贵的记忆并带来额外的表现   由于额外的飞行缩放而产生的开销。