Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/image/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android 设置视图背景会导致OutOfMemory错误_Android_Image_Android Studio_Out Of Memory - Fatal编程技术网

Android 设置视图背景会导致OutOfMemory错误

Android 设置视图背景会导致OutOfMemory错误,android,image,android-studio,out-of-memory,Android,Image,Android Studio,Out Of Memory,我只是想更改应用程序的背景图像,它还没有任何内容,我只是想将主要活动的背景更改为图像。 它在预览中正确显示,但当我在模拟器或物理设备上运行它时,会出现此错误 抛出OutOfMemoryError“无法分配604786188字节 分配4194208个可用字节和230MB,直到OOM“ 该图像小于1.5MB,因此我不知道它为什么会耗尽内存或试图分配这么多 我所做的只是打开一个空白项目并更改相对布局的背景 奇怪的是,如果我在Nexus4模拟器上运行该应用程序,它可以正常工作,但即使在android上的

我只是想更改应用程序的背景图像,它还没有任何内容,我只是想将主要活动的背景更改为图像。 它在预览中正确显示,但当我在模拟器或物理设备上运行它时,会出现此错误

抛出OutOfMemoryError“无法分配604786188字节 分配4194208个可用字节和230MB,直到OOM“

该图像小于1.5MB,因此我不知道它为什么会耗尽内存或试图分配这么多

我所做的只是打开一个空白项目并更改相对布局的背景

奇怪的是,如果我在Nexus4模拟器上运行该应用程序,它可以正常工作,但即使在android上的同一版本上运行Nexus5,也会抛出此错误

编辑

不再获取上述错误,而是在应用程序启动时发生以下错误,无论使用的是什么模拟器

FATAL EXCEPTION: main
    Process: com.jacksteel.comp4, PID: 2164
    java.lang.RuntimeException: Unable to instantiate activity ComponentInfo{com.jacksteel.comp4/com.jacksteel.comp4.MainActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'android.view.View android.view.Window.findViewById(int)' on a null object reference
            at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2236)
            at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2390)
            at android.app.ActivityThread.access$800(ActivityThread.java:151)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1303)
            at android.os.Handler.dispatchMessage(Handler.java:102)
            at android.os.Looper.loop(Looper.java:135)
            at android.app.ActivityThread.main(ActivityThread.java:5257)
            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:903)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)
     Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'android.view.View android.view.Window.findViewById(int)' on a null object reference
            at android.app.Activity.findViewById(Activity.java:2072)
            at com.jacksteel.comp4.MainActivity.<init>(MainActivity.java:20)
            at java.lang.reflect.Constructor.newInstance(Native Method)
            at java.lang.Class.newInstance(Class.java:1606)
            at android.app.Instrumentation.newActivity(Instrumentation.java:1066)
            at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2226)
            at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2390)
            at android.app.ActivityThread.access$800(ActivityThread.java:151)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1303)
            at android.os.Handler.dispatchMessage(Handler.java:102)
            at android.os.Looper.loop(Looper.java:135)
            at android.app.ActivityThread.main(ActivityThread.java:5257)
            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:903)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)
编辑3更新

更新的源代码

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    final RelativeLayout Bg = (RelativeLayout) findViewById(R.id.MainBg);

    Bg.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            Bg.getViewTreeObserver().removeGlobalOnLayoutListener(this);
            Bitmap bitmap = decodeSampledBitmapFromResource(getResources(), R.drawable.redboxes, Bg.getWidth(), Bg.getHeight());
            Resources res = getResources();
            BitmapDrawable backgroundDrawable = new BitmapDrawable(res, bitmap);
            Bg.setBackgroundDrawable(backgroundDrawable);
        }
    });

}
更新错误

FATAL EXCEPTION: main
    Process: com.jacksteel.comp4, PID: 1872
    java.lang.OutOfMemoryError: Failed to allocate a 107347980 byte allocation with 1048576 free bytes and 63MB until OOM
            at dalvik.system.VMRuntime.newNonMovableArray(Native Method)
            at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method)
            at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:609)
            at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:444)
            at android.graphics.BitmapFactory.decodeResource(BitmapFactory.java:467)
            at com.jacksteel.comp4.MainActivity.decodeSampledBitmapFromResource(MainActivity.java:93)
            at com.jacksteel.comp4.MainActivity$1.onGlobalLayout(MainActivity.java:27)
            at android.view.ViewTreeObserver.dispatchOnGlobalLayout(ViewTreeObserver.java:912)
            at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1881)
            at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1061)
            at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:5885)
            at android.view.Choreographer$CallbackRecord.run(Choreographer.java:767)
            at android.view.Choreographer.doCallbacks(Choreographer.java:580)
            at android.view.Choreographer.doFrame(Choreographer.java:550)
            at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:753)
            at android.os.Handler.handleCallback(Handler.java:739)
            at android.os.Handler.dispatchMessage(Handler.java:95)
            at android.os.Looper.loop(Looper.java:135)
            at android.app.ActivityThread.main(ActivityThread.java:5257)
            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:903)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)

更新

您应该将要加载的图像与
BitmapFactory.decodeResource()
一起放入
drawable nodpi
目录,以避免从
drawable-
目录名中使用的密度缩放到设备屏幕密度

在您的情况下,您将图像放在
可绘制hdpi
目录中,并且您的设备具有
xxhdpi
屏幕,因此在
BitmapFactory.decodeResource()
inSampleSize=2
图像放大了2倍(从
hdpi
xxhdpi
),缩小了2倍(通过
inSampleSize
)保持原始大小,并通过
OutOfMemoryError
导致应用程序崩溃

原始答案

1.5MB是压缩图像的大小。当您将其加载到
ImageView
或某个其他视图的背景时,将隐式创建
位图
。在
位图中
图像的每个像素占用4个字节。所以,如果您的图像的分辨率为4096x4096像素,则需要64兆字节的内存,尽管图像可以用单色填充,并且只需要压缩为png或jpeg的几千字节

您应该确定视图的实际大小并加载缩放图像:

view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            view.getViewTreeObserver().removeGlobalOnLayoutListener(this);
            Bitmap bitmap = ImageUtils.decodeSampledBitmapFromFile(backgroundImageFile, view.getWidth(), view.getHeight());
            view.setBackground(new BitmapDrawable(getResources(), bitmap));
        }
    });
我的实用方法是从
文件
加载缩放的
位图

public class ImageUtils {
    public static Bitmap decodeSampledBitmapFromFile(File file, int reqWidth, int reqHeight) {

        // First decode with inJustDecodeBounds=true to check dimensions
        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(file.getAbsolutePath(), options);

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

        // Decode bitmap with inSampleSize set
        options.inJustDecodeBounds = false;
        return BitmapFactory.decodeFile(file.getAbsolutePath(), options);
    }

     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) {

            // Calculate ratios of height and width to requested height and width
            final int heightRatio = Math.floor((float) height / (float) reqHeight);
            final int widthRatio = Math.floor((float) width / (float) reqWidth);

            // Choose the smallest ratio as inSampleSize value, this will guarantee
            // a final image with both dimensions larger than or equal to the
            // requested height and width.
            inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
        }

        return inSampleSize;
    }
}
公共类ImageUtils{
公共静态位图解码SampledBitMapFromFile(文件文件文件,int-reqWidth,int-reqHeight){
//使用INJUSTDECBOUNDS首次解码=true检查尺寸
final BitmapFactory.Options=new BitmapFactory.Options();
options.inJustDecodeBounds=true;
BitmapFactory.decodeFile(file.getAbsolutePath(),选项);
//计算样本大小
options.inSampleSize=计算样本大小(options、reqWidth、reqHeight);
//使用inSampleSize集合解码位图
options.inJustDecodeBounds=false;
返回BitmapFactory.decodeFile(file.getAbsolutePath(),options);
}
公共静态int-calculateInSampleSize(BitmapFactory.Options选项、int-reqWidth、int-reqHeight){
//图像的原始高度和宽度
最终内部高度=options.outHeight;
最终整数宽度=options.outWidth;
int inSampleSize=1;
如果(高度>要求高度| |宽度>要求宽度){
//计算高度和宽度与所需高度和宽度的比率
最终内部高度比=数学地板((浮动)高度/(浮动)要求高度);
最终内部宽度比=数学地板((浮动)宽度/(浮动)宽度);
//选择最小比率作为采样值,这将保证
//最终图像的两个尺寸均大于或等于
//要求的高度和宽度。
inSampleSize=高度比<宽度比?高度比:宽度比;
}
返回样本大小;
}
}

您可以使用其他
位图工厂
方法从流、资源和字节数组中解码
位图。

更新

您应该将要加载的图像与
BitmapFactory.decodeResource()
一起放入
drawable nodpi
目录,以避免从
drawable-
目录名中使用的密度缩放到设备屏幕密度

在您的情况下,您将图像放在
可绘制hdpi
目录中,并且您的设备具有
xxhdpi
屏幕,因此在
BitmapFactory.decodeResource()
inSampleSize=2
图像放大了2倍(从
hdpi
xxhdpi
),缩小了2倍(通过
inSampleSize
)保持原始大小,并通过
OutOfMemoryError
导致应用程序崩溃

原始答案

1.5MB是压缩图像的大小。当您将其加载到
ImageView
或某个其他视图的背景时,将隐式创建
位图
。在
位图中
图像的每个像素占用4个字节。所以,如果您的图像的分辨率为4096x4096像素,则需要64兆字节的内存,尽管图像可以用单色填充,并且只需要压缩为png或jpeg的几千字节

您应该确定视图的实际大小并加载缩放图像:

view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            view.getViewTreeObserver().removeGlobalOnLayoutListener(this);
            Bitmap bitmap = ImageUtils.decodeSampledBitmapFromFile(backgroundImageFile, view.getWidth(), view.getHeight());
            view.setBackground(new BitmapDrawable(getResources(), bitmap));
        }
    });
我的实用方法是从
文件
加载缩放的
位图

public class ImageUtils {
    public static Bitmap decodeSampledBitmapFromFile(File file, int reqWidth, int reqHeight) {

        // First decode with inJustDecodeBounds=true to check dimensions
        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(file.getAbsolutePath(), options);

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

        // Decode bitmap with inSampleSize set
        options.inJustDecodeBounds = false;
        return BitmapFactory.decodeFile(file.getAbsolutePath(), options);
    }

     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) {

            // Calculate ratios of height and width to requested height and width
            final int heightRatio = Math.floor((float) height / (float) reqHeight);
            final int widthRatio = Math.floor((float) width / (float) reqWidth);

            // Choose the smallest ratio as inSampleSize value, this will guarantee
            // a final image with both dimensions larger than or equal to the
            // requested height and width.
            inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
        }

        return inSampleSize;
    }
}
公共类ImageUtils{
公共静态位图解码SampledBitMapFromFile(文件文件文件,int-reqWidth,int-reqHeight){
//使用INJUSTDECBOUNDS首次解码=true检查尺寸
final BitmapFactory.Options=new BitmapFactory.Options();
options.inJustDecodeBounds=true;
BitmapFactory.decodeFile(file.getAbsolutePath(),选项);
//计算样本大小
options.inSampleSize=计算样本大小(options、reqWidth、reqHeight);
//使用inSampleSize s解码位图