如何使用LayerDrawable解决OutOfMemoryError问题

5

错误:

java.lang.OutOfMemoryError
at android.graphics.Bitmap.nativeCreate(Native Method)
at android.graphics.Bitmap.createBitmap(Bitmap.java:605)
at android.graphics.Bitmap.createBitmap(Bitmap.java:551)
at android.graphics.Bitmap.createScaledBitmap(Bitmap.java:437)
at android.graphics.BitmapFactory.finishDecode(BitmapFactory.java:618)
at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:593)
at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:445)
at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:775)
at android.content.res.Resources.loadDrawable(Resources.java:1968)
at android.content.res.Resources.getDrawable(Resources.java:677)
at android.widget.ImageView.resolveUri(ImageView.java:542)
at android.widget.ImageView.setImageResource(ImageView.java:315)
at app.Main.GridActivity.initaliseLevel(GridActivity.java:245)
at app.Main.GridActivity.load_player_settings(GridActivity.java:180)
at app.Main.GridActivity.onResume(GridActivity.java:79)
at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1158)
at android.app.Activity.performResume(Activity.java:4607)
at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2448)
at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2486)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2000)
at android.app.ActivityThread.access$600(ActivityThread.java:128)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1161)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4517)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:993)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:760)
at dalvik.system.NativeStart.main(Native Method)

图片是通过以下方式设置的:
ImageButton b0 = (ImageButton) findViewById(R.id.ImageButton00);
Resources r = getResources();
Drawable[] layers = new Drawable[2];
layers[0] = r.getDrawable(R.drawable.image);
layers[1] = r.getDrawable(R.drawable.imagetwo);
LayerDrawable layerDrawable = new LayerDrawable(layers);
b0.setImageDrawable(layerDrawable);

从阅读其他答案中,我了解到图片在使用后需要进行回收。这是最好的选择吗?如果是,如何将LayerDrawable转换为位图,以便可以回收?


你正在尝试加载的图像尺寸是多少(宽 x 高)? - dumbfingers
我遇到了类似的问题。图片都相当小。如果我把除了一个图片以外的所有东西注释掉,就没有问题,但是其他任何东西都会使它崩溃。第一张图片有透明度设置……不确定是否会导致这个问题? - RiddlerDev
你是否在模拟器中测试?如果是,你的“最大VM应用程序堆大小”有多大?你可以增加它以确定你的程序实际使用了多少内存吗? - happydude
我正在使用S3和模拟器进行测试,但我仍然没有解决这个问题。不过,我通过将我的图像回调设置为null并确保销毁我的广告视图来减少了内存泄漏的数量。 - Isaac
很抱歉,system.gc()并不能保证垃圾回收器一定会运行。请参考http://developer.android.com/reference/java/lang/System.html#gc%28%29。 - Isaac
显示剩余4条评论
1个回答

2
在您的清单文件中的应用程序属性部分,有一个“大堆”设置,在应用程序节点中选择您的活动,然后在堆设置中选择“true”,这对我有所帮助,直到我解决了泄漏问题。
此外,我的活动中也有以下内容:
private void unbindDrawables(View view) {
    if (view.getBackground() != null) {
        view.getBackground().setCallback(null);
    }
    if (view instanceof ViewGroup) {
        for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) {
            unbindDrawables(((ViewGroup) view).getChildAt(i));
        }
        ((ViewGroup) view).removeAllViews();
    }
}

    @Override
protected void onDestroy() {
    super.onDestroy();

    unbindDrawables(findViewById(R.id.nameslayout));
    System.gc();
}

希望这能帮到您。

您太厉害了!这让我至少能够在手机上加载屏幕,以便我可以继续优化。我会确保添加您的GC内容,因为那看起来很不错。谢谢! - RiddlerDev

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接