【问题标题】:Exception : OutOfMemoryError异常:OutOfMemoryError
【发布时间】:2014-02-15 09:20:25
【问题描述】:

我已在 Play 商店中发布了我的应用程序。现在在崩溃和 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;
    }
}

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

【问题讨论】:

  • 你能展示你的代码吗?
  • 从发布 Buddha4.java 开始。无论如何,您似乎正在尝试加载 BIIIIIIIG 图像
  • 我在 Play 商店中收到 5 页错误的报告。在 com.info.laughingbuddha.Buddha4.onCreateView(Buddha4.java:21)
  • 只有类名发生变化,即Buddha3、Buddha2和一个Buddha4以上。
  • @SanketKachhela 我已经编辑了我的代码。请帮我解决这个问题。

标签: android out-of-memory


【解决方案1】:

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

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?

【讨论】:

  • 我必须在上面的代码中使用一些数字而不是高度和宽度?
  • 是的,您必须根据您的设备尺寸和密度来计算。 @JohnR
  • @JohnR 如果此答案对您有帮助,请接受答案
  • @JohnR 你找到解决方案了吗?
  • 安德鲁建议的答案是正确的。我只在 drawable-mdpi 文件夹中使用所有图像。但是他提供的解决方案并不好,因为我想为大屏幕缩放图像。
【解决方案2】:

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

检查更多关于“内存问题”:

Load a Scaled Down Version into Memory 下的主题。
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

在将可绘制对象设置为图像视图的背景之前,即:

iv.setBackgroundResource(R.drawable.buddha4);  

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

【讨论】:

    【解决方案3】:

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

    从您的崩溃日志看来,您有相当大的可绘制对象,因此为了避免OutOfMemory,您必须保留不会占用太多内存的可绘制对象。您可以按照一些人在答案中的建议缩小可绘制对象。

    如果您不想这样做,并且您没有太多大尺寸可绘制对象,那么您可以选择将应用程序堆大小增加到可以增加堆内存的大尺寸。

    如何增加堆大小

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

    在 2.3 之前的设备上,您可以使用 VMRuntime 类,但这不适用于 Gingerbread 及更高版本,请参阅下文。

    VMRuntime.getRuntime().setMinimumHeapSize(BIGGER_SIZE);
    

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

    在设置之前,只需检查您的应用需要多少大小,然后设置大小以完成您的工作。不要使用太多内存,否则可能会影响其他应用程序。

    更新

    注意:最好的做法是在不再需要位图时释放分配的内存,你可以bitmap.recycle()

    【讨论】:

    • 但是为什么这些错误不会出现在任何其他设备上,即使这些设备具有旧的 API 版本。为什么只在这 2 台设备上?
    • @JohnR 这不是专门针对这些的,您将来在其他设备上也可能会遇到同样的错误,您的代码中没有错误,但在运行时占用的内存比 Android OS 选择的可用内存要多在这些设备中杀死应用程序。
    • 如果我在清单文件中尝试 largeHeap 属性。解决这个问题就够了吗?
    • @JohnR 是的,很可能它会解决问题,但请阅读我的完整答案,我写了这会产生什么影响
    • 我使用的是最低版本 8。所以我必须使用哪种解决方案。我对你的回答有点困惑。
    【解决方案4】:

    我遇到过几次的一个问题是有很多 MDPI 可绘制资源,但没有 HDPI / XHDPI 版本。在 HDPI 或 XHDPI 设备上加载这些文件时,Android 将通过加载原始文件来放大它们,然后在内存中制作一个放大的副本,这意味着您在内存中一次有两个副本,原始版本和放大版本。如果渲染器正在拉伸可绘制对象(例如,如果它是视图的背景),那么 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"
    

    【讨论】:

    • +1 非常感谢您。我在 mdpi 文件夹中有所有图像。我从来没有在这里提到过。我没有使用任何其他可绘制对象来缩小应用程序大小。
    • 我想要缩放图像。那么还有其他选择吗?
    • 您可以通过设置 android:scaleType 属性来使用图像视图上可用的缩放。例如。您可以将图像视图的宽度和高度设置为 match_parent,然后将缩放类型设置为 centerCrop 或 centerInside 以在绘制图像时放大图像,同时保持其纵横比。 centerCrop 将完全填充图像视图,但可能会切断一些图像,而 centerInside 确保整个图像可见,但可能会留下一些空白空间。缩放将在渲染时完成,因此不会使用任何额外的内存。
    • 你应该得到这个赏金。但是,当您为上述评论提供一些代码时,我接受您的回答。
    • 这一切都可以在布局 XML 中完成,如下所示:android:layout_height="match_parent" android:layout_width="match_parent" android:scaleType="centerCrop"
    【解决方案5】:

    你必须在加载时缩小你的图片资源。

    如果您正在加载图像,使用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;
    }
    

    【讨论】:

      【解决方案6】:

      如果您不确定图像的大小,请不要直接加载 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;
      }
      

      【讨论】:

        【解决方案7】:

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

        如果您使用的是位图

        使用

         bitmap.recycle();
        

        当你使用它时。

        你可以使用

         android:largeHeap="true"
        

        在 manifest.xml 中增加堆大小。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-11-06
          • 1970-01-01
          • 2014-04-25
          相关资源
          最近更新 更多