例外:OutOfMemoryError

时间:2014-02-15 09:20:25

标签: android out-of-memory

我在Play商店发布了我的应用程序。现在在Crashes和ANR中,我在2个设备上遇到错误(Galaxy Note3和Galaxy Note II)。我不知道如何解决这些错误,这是什么类型的错误?所以请帮我解决这些错误。在其他设备上,我没有收到任何报告。

错误 -

java.lang.OutOfMemoryError
at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method)
at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:677)
at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:507)
at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:872)
at android.content.res.Resources.loadDrawable(Resources.java:3022)
at android.content.res.Resources.getDrawable(Resources.java:1586)
at android.view.View.setBackgroundResource(View.java:16120)
at com.info.laughingbuddha.Buddha4.onCreateView(Buddha4.java:21)
at android.support.v4.app.Fragment.performCreateView(Fragment.java:1500)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:927)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1104)
at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:682)
at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1467)
at android.support.v4.app.FragmentManagerImpl.executePendingTransactions(FragmentManager.java:472)
at android.support.v4.app.FragmentStatePagerAdapter.finishUpdate(FragmentStatePagerAdapter.java:163)
at android.support.v4.view.ViewPager.populate(ViewPager.java:1068)
at android.support.v4.view.ViewPager.populate(ViewPager.java:914)
at android.support.v4.view.ViewPager$3.run(ViewPager.java:244)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:803)
at android.view.Choreographer.doCallbacks(Choreographer.java:603)
at android.view.Choreographer.doFrame(Choreographer.java:572)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:789)
at android.os.Handler.handleCallback(Handler.java:733)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:157)
at android.app.ActivityThread.main(ActivityThread.java:5293)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1259)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1075)
at dalvik.system.NativeStart.main(Native Method)

Buddha4.java -

package com.info.laughingbuddha;


import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.text.method.ScrollingMovementMethod;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;

public class Buddha4 extends Fragment{

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View rootView = inflater.inflate(R.layout.buddha, container, false);
    TextViewEx t = (TextViewEx) rootView.findViewById(R.id.textView2);
    t.setText("The Standing Happy Buddha brings riches and happiness.",true);
    t.setMovementMethod(new ScrollingMovementMethod());
    ImageView iv = (ImageView) rootView.findViewById(R.id.image1);
    iv.setBackgroundResource(R.drawable.buddha4);
    return rootView;
    }
}

我不知道我需要发布什么代码,所以如果有人需要任何与此相关的代码,请发表评论。感谢。

7 个答案:

答案 0 :(得分:6)

尝试使用以下代码行创建缩放位图:

Bitmap scaledBitmap = Bitmap.createScaledBitmap(myBitmap, width,
                height, true);

检查以下链接:

android - out of memory exception when creating bitmap

Android out of memory exception with bitmaps

Can I catch out of memory exception in Android in Bitmap allocation for decoding a picture file?

答案 1 :(得分:2)

如果您有高分辨率图像,则应将其缩小以避免不同设备加载图像而不会遇到内存问题。 在您的情况下,某些手机在首次运行时可能不会表现出相同的行为,但最终,如果不处理优化的图像加载解决方案,应用程序将崩溃。

检查“内存问题”:

将缩小版本加载到内存中的主题。
http://developer.android.com/training/displaying-bitmaps/load-bitmap.html
Out of memory error on Android

关于如何避免它们:
How to avoid an out of memory error while using bitmaps in Android

概述:
http://blogs.innovationm.com/android-out-of-memory-error-causes-solution-and-best-practices/ http://android-developers.blogspot.de/2009/01/avoiding-memory-leaks.html

在将drawable设置为imageview的背景之前,即:

iv.setBackgroundResource(R.drawable.buddha4);  

正如@ rup35h在答案中建议的那样,获取缩放位图或尝试其他选项,例如inSampleSize,请检查您的解决方案如何影响图像质量。

答案 2 :(得分:2)

有时当我们使用这么多图像时在应用程序中的背景,它需要在Android RAM上占用大量空间。 这导致强制通过“Out of memory Bound Exception”关闭您的应用程序。

从你的崩溃日志中可以看出,你有一个非常大的drawable,所以为了避免OutOfMemory你保留了不会占用太多内存的drawable。你可以按照一些人在答案中建议的那样缩小抽象。

如果你不想通过它并且你没有太大的可绘制大小,那么你可以选择将应用程序堆大小增加到大,这会增加堆内存。

  

如何增加堆大小

您可以在Android清单的应用程序标记中使用android:largeHeap="true"(此处参考)来请求更大的堆大小,但这不适用于任何预先 蜂窝设备。

在2.3之前的设备上,您可以使用VMRuntime类,但这不适用于Gingerbread及以上版本。请参阅下面的操作方法。

VMRuntime.getRuntime().setMinimumHeapSize(BIGGER_SIZE);

在设置HeapSize之前,请确保您输入的大小不会影响其他应用程序或操作系统功能。

在设置之前,只需检查您的应用需要多大的尺寸&然后设置大小只是为了完成你的工作。不要使用这么多内存,否则其他应用程序可能会影响。

更新

注意:最好不要再使用已经分配的位图内存,这可以是bitmap.recycle()

答案 3 :(得分:1)

我曾经遇到的一个问题是拥有大量MDPI可绘制资源但没有HDPI / XHDPI版本。在HDPI或XHDPI设备上加载这些设备时,Android会通过加载原始设备来扩展它们,然后在内存中制作一个放大的副本,这意味着您一次在内存中有两个副本,原始版本和按比例放大的版本。如果渲染器正在拉伸drawable(例如,如果它是视图的背景),那么在加载时Android不需要扩展它,因为渲染器无论如何都会这样做。因此,如果您只有一个图像的MDPI副本并且不希望Android进行扩展,则应将其放在drawable-nodpi文件夹而不是drawable或drawable-mdpi文件夹中。

修改

您可以通过设置android:scaleType属性来使用图像视图上可用的渲染时间缩放。例如。您可以将图像视图的宽度和高度设置为match_parent,然后将比例类型设置为centerCrop或centerInside,以便在保持其纵横比的同时将图像放大。 centerCrop将完全填充图像视图,但可能会截断一些图像,而centerInside确保整个图像可见,但可能留下一些空白。缩放将在渲染时完成,因此不会使用任何额外的内存。

这一切都可以在布局XML中完成,如下所示:

android:layout_height="match_parent"
android:layout_width="match_parent"
android:scaleType="centerCrop"

要使图像完全显示在图像视图内而不进行裁剪,请将最后一行更改为:

android:scaleType="centerInside"

最后,如果您不想保持纵横比,可以使用以下比例类型:

android:scaleType="fitXY"

答案 4 :(得分:0)

加载图像资源时必须缩小图像资源。

如果您使用Bitmap变量加载图片,则可以使用inSample使用BitmapFactory.Options选项。不要使用Bitmap.createScaledBitmap因为它会创建除原始位图之外的另一个位图!

尝试使用以下代码加载位图:

BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true; //This will just get the size of your image
BitmapFactory.decodeFile(pictureFile.getAbsolutePath(), options);
//Get the downscale ratio
options.inJustDecodeBounds = false;
options.inSampleSize = calculateInSampleSize(options, widthOfTheImageView, heightOfTheImageView);
//Decode the bitmap using the downsampled image
Bitmap finalBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.image_name options);
//Finally, set the bitmap
imageView.setImageBitmap(finalBitmap);

widthOfTheImageViewheightOfTheImageView代表ImageView的大小。

calculateInSampleSize方法(我是从Android开发者tutorial获得的):

public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
    // Raw height and width of image
    final int height = options.outHeight;
    final int width = options.outWidth;
    int inSampleSize = 1;

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

        final int halfHeight = height / 2;
        final int halfWidth = width / 2;

        // Calculate the largest inSampleSize value that is a power of 2 and keeps both
        // height and width larger than the requested height and width.
        while ((halfHeight / inSampleSize) > reqHeight
                && (halfWidth / inSampleSize) > reqWidth) {
            inSampleSize *= 2;
        }
    }
    return inSampleSize;
}

答案 5 :(得分:0)

如果您不确定图像的大小,请不要直接加载Bitmap。当尺寸太大时请对其进行取样。在大多数情况下,加载的图像长度不应超过手机屏幕的长度。使用这样的代码来拍摄图像。

public static Bitmap loadImage(Context cx, Uri uri, int maxLength) {
    InputStream is = cx.getContentResolver().openInputStream(uri);
    Options opts = new Options();
    opts.inJustDecodeBounds = true;
    BitmapFactory.decodeStream(is, null, opts);
    int length = Math.max(opts.outWidth, opts.outHeight);
    int n = 1;
    while (length > maxLength) {
        maxLength /= 2;
        n ++;
    }
    is = cx.getContentResolver().openInputStream(uri);
    opts.inJustDecodeBounds = false;
    opts.inPurgeable = true;
    opts.inDither = true;
    opts.inPurgeable = true;
    opts.inSampleSize = sample;
    Bitmap bm = BitmapFactory.decodeStream(is, null, opts);
    return bm;
}

答案 6 :(得分:0)

退出活动时删除所有视图。在OnDestroy()中将其设为null

如果您使用的是Bitmaps

使用

 bitmap.recycle();

当你使用它时。

你可以使用

 android:largeHeap="true"
在manifest.xml中

增加堆大小。