Android : java.lang.OutOfMemoryError:

13

我开发了一个在Android上使用大量图片的应用程序。

在drawable文件夹中有很多的图片,比如超过100张,我正在为图片动画开发应用程序。我使用ImageView来显示GIF图像。我已经使用了将GIF图像拆分成多个PNG格式图像的概念并使用它。

每次用户进入应用程序时,我可以看到内存越来越多,直到用户得到java.lang.OutOfMemoryError

那么处理许多图片的最佳/正确方法是什么?

以下是我的代码:

dog_animation.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/DogView"
android:orientation="vertical" >

<ImageView
    android:id="@+id/dog_animation"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_weight="0.19" />

dog_animation.xml(Drawable文件夹)

<?xml version="1.0" encoding="utf-8"?>

<item
    android:drawable="@drawable/image"
    android:duration="50"/>
<item
    android:drawable="@drawable/image1"
    android:duration="50"/>
<item
    android:drawable="@drawable/image2"
    android:duration="50"/>
<item
    android:drawable="@drawable/image3"
    android:duration="50"/>
<item
    android:drawable="@drawable/image4"
    android:duration="50"/>
<item
    android:drawable="@drawable/image5"
    android:duration="50"/>
<item
    android:drawable="@drawable/image6"
    android:duration="50"/>
<item
    android:drawable="@drawable/image7"
    android:duration="50"/>
<item
    android:drawable="@drawable/image8"
    android:duration="50"/>
<item
    android:drawable="@drawable/image9"
    android:duration="50"/>
<item
    android:drawable="@drawable/image10"
    android:duration="50"/>
<item
    android:drawable="@drawable/image11"
    android:duration="50"/>
<item
    android:drawable="@drawable/image12"
    android:duration="50"/>
<item
    android:drawable="@drawable/image13"
    android:duration="50"/>
<item
    android:drawable="@drawable/image14"
    android:duration="50"/>
<item
    android:drawable="@drawable/image15"
    android:duration="50"/>
<item
    android:drawable="@drawable/image16"
    android:duration="50"/>
<item
    android:drawable="@drawable/image17"
    android:duration="50"/>
<item
    android:drawable="@drawable/image18"
    android:duration="50"/>
<item
    android:drawable="@drawable/image19"
    android:duration="50"/>
<item
    android:drawable="@drawable/image20"
    android:duration="50"/>
<item
    android:drawable="@drawable/image21"
    android:duration="50"/>
<item
    android:drawable="@drawable/image22"
    android:duration="50"/>
<item
    android:drawable="@drawable/image23"
    android:duration="50"/>
<item
    android:drawable="@drawable/image24"
    android:duration="50"/>
<item
    android:drawable="@drawable/image25"
    android:duration="50"/>
<item
    android:drawable="@drawable/image26"
    android:duration="50"/>
<item
    android:drawable="@drawable/image27"
    android:duration="50"/>
<item
    android:drawable="@drawable/image28"
    android:duration="50"/>
<item
    android:drawable="@drawable/image29"
    android:duration="50"/>
<item
    android:drawable="@drawable/image30"
    android:duration="50"/>
<item
    android:drawable="@drawable/image31"
    android:duration="50"/>
<item
    android:drawable="@drawable/image32"
    android:duration="50"/>
<item
    android:drawable="@drawable/image33"
    android:duration="50"/>
<item
    android:drawable="@drawable/image34"
    android:duration="50"/>
<item
    android:drawable="@drawable/image35"
    android:duration="50"/>
<item
    android:drawable="@drawable/image36"
    android:duration="50"/>
<item
    android:drawable="@drawable/image37"
    android:duration="50"/>
<item
    android:drawable="@drawable/image38"
    android:duration="50"/>
<item
    android:drawable="@drawable/image39"
    android:duration="50"/>
<item
    android:drawable="@drawable/image40"
    android:duration="50"/>
<item
    android:drawable="@drawable/image41"
    android:duration="50"/>
<item
    android:drawable="@drawable/image42"
    android:duration="50"/>
<item
    android:drawable="@drawable/image43"
    android:duration="50"/>
<item
    android:drawable="@drawable/image44"
    android:duration="50"/>
<item
    android:drawable="@drawable/image45"
    android:duration="50"/>
<item
    android:drawable="@drawable/image46"
    android:duration="50"/>
<item
    android:drawable="@drawable/image47"
    android:duration="50"/>
<item
    android:drawable="@drawable/image48"
    android:duration="50"/>
<item
    android:drawable="@drawable/image49"
    android:duration="50"/>
<item
    android:drawable="@drawable/image50"
    android:duration="50"/>
<item
    android:drawable="@drawable/image51"
    android:duration="50"/>
<item
    android:drawable="@drawable/image52"
    android:duration="50"/>
<item
    android:drawable="@drawable/image53"
    android:duration="50"/>
<item
    android:drawable="@drawable/image54"
    android:duration="50"/>
<item
    android:drawable="@drawable/image55"
    android:duration="50"/>
<item
    android:drawable="@drawable/image56"
    android:duration="50"/>

Dog_Animation.java

public class Dog_Animation extends Activity {

Timer timer = new Timer();

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    requestWindowFeature(Window.FEATURE_NO_TITLE);
    getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
            WindowManager.LayoutParams.FLAG_FULLSCREEN);
    setContentView(R.layout.dog_animation);

    ImageView img = (ImageView) findViewById(R.id.dog_animation);
    img.setBackgroundResource(R.drawable.dog_animation);
    AnimationDrawable frameAnimation = (AnimationDrawable) img
            .getBackground();
    frameAnimation.start();

    timer.schedule(new TimerTask() {
        public void run() {
            Intent intent = new Intent(Dog_Animation.this,
                    Man_Animation.class);
            startActivity(intent);
        }
    }, 10000);
}
}

现在的问题是当我尝试从一个activity移动到另一个activity,并且这个activity中有某些其他图像需要进行动画处理时,它会给出“java.lang.OutOfMemory”错误。

我已经尝试了许多不同的解决方案,比如

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

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

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();
    }
}

还有其他的方法,但是对我都不起作用。请帮我解决这个问题。我甚至参考了http://androidactivity.wordpress.com/2011/09/24/solution-for-outofmemoryerror-bitmap-size-exceeds-vm-budget/ 这个链接,但是问题仍未得到解决。


最好的方法是在这里或谷歌上搜索。有很多答案。 - Simon
嗨,西蒙,我尝试并在Google中搜索了很多,但没有得到适当的解决方案。这就是我提出这个问题的唯一原因。 - InnocentKiller
看起来你的应用程序存在内存泄漏问题。你尝试过按照这里的教程进行操作吗:http://android-developers.blogspot.kr/2011/03/memory-analysis-for-android.html(同时,还有相应的Google I/O讲座可供参考)? - sandrstar
嘿,sandrstar,我还没有尝试你提供的解决方法,但我肯定会尝试并告诉你它是否在我的情况下有效。感谢您的建议。 - InnocentKiller
显示剩余2条评论
6个回答

20
在你的AndroidManifest.xml文件中,在application标签内添加largeHeap,像这样:
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:largeHeap="true"/>

3
尝试在onPause()中停止您的动画。很可能是因为这个原因导致它没有得到垃圾回收。 此外,使用此网站http://tinypng.org优化您的位图。如果不需要alpha层,请将其设置为24位。

1
替换:
img.setBackgroundResource(R.drawable.dog_animation);

通过:

img.setImageBitmap(decodeSampleBitmapFromResource(R.drawable.dog_animation, width, height));
//dont forget to replace width and heigh by your imageview dimension

一个补充:

public static int calculateInSampleSize(
            BitmapFactory.Options options, int reqWidth, int reqHeight) {

    final int height = options.outHeight;
    final int width = options.outWidth;
    int inSampleSize = 1;

    if (height > reqHeight || width > reqWidth) {

        final int heightRatio = Math.round((float) height / (float) reqHeight);
        final int widthRatio = Math.round((float) width / (float) reqWidth);

        inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
    }

    return inSampleSize;
}

并且

public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
        int reqWidth, int reqHeight) {

    final BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeResource(res, resId, options);

    options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

    options.inJustDecodeBounds = false;
    return BitmapFactory.decodeResource(res, resId, options);
}

这是来自于: http://developer.android.com/training/displaying-bitmaps/load-bitmap.html

1
在上面的答案中,缺少一个getResources()
img.setImageBitmap(decodeSampleBitmapFromResource(R.drawable.dog_animation, width, height));

所以它变成了。
img.setImageBitmap(decodeSampleBitmapFromResource(getResources(), R.drawable.dog_animation, width, height));

0
几天前,我遇到了同样的问题,并生成了类似的日志。以下是我解决问题的方法。
我了解到,在Android Studio中加载到ImageView中的图像的像素不得超过宽度1440和高度2560。 stackoverflow上最受欢迎的解决方案是在我们的清单文件中添加以下内容:android:hardwareAccelerated="false",android:largeHeap="true" 就像这张图片所示 当我实施这个解决方案时,错误没有被抛出,但这并不适用于所有设备,而只适用于我的模拟器。
因此,为了解决我的手机的这个问题,我简单地将相关图像裁剪到限制像素后,检查每个图像的像素并丢弃太大以进行裁剪(调整大小)的图像。注意:对于大量的图像,您可以编写代码来检查超过所需像素数量的图像。

这是我在github.com上的问题链接(allenbangai


-5
try {
    //Code here that cause OutOfMemoryError
} catch (Error ee) {
    ee.printStacktrace();
}

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