【问题标题】:Out of memory on a 16571536 byte allocation16571536 字节分配内存不足
【发布时间】:2014-03-05 10:15:05
【问题描述】:

基本上,我正在为 android 4.4.2 锁屏背景添加一个壁纸选择器,当图像设置好并且我关闭屏幕然后重新打开以查看锁屏时,我的屏幕变黑了,而 logcat 让我退出内存分配错误。到目前为止,我已经尝试使用 Bitmap decodeFile(String pathName) 并且我也重新设置为使用 Bitmap decodeFile(String pathName, Options opts) 但每次结果都是一样的......

这是设置图像的原始方法:

private static final String WALLPAPER_IMAGE_PATH =
        "/data/data/com.android.settings/files/lockscreen_wallpaper.png";

private KeyguardUpdateMonitorCallback mBackgroundChanger = new KeyguardUpdateMonitorCallback() {
    @Override
    public void onSetBackground(Bitmap bmp) {
        if (bmp != null) {
            mKeyguardHost.setCustomBackground(
                    new BitmapDrawable(mContext.getResources(), bmp));
        }
        else {
            File file = new File(WALLPAPER_IMAGE_PATH);
            if (file.exists()) {
                mKeyguardHost.setCustomBackground(
                        new BitmapDrawable(mContext.getResources(), WALLPAPER_IMAGE_PATH));
            }
            else {
                mKeyguardHost.setCustomBackground(null);
            }
        }
        updateShowWallpaper(bmp == null);
    }
};

从案例 1 中调用:

    public void setCustomBackground(Drawable d) {
        if (!mAudioManager.isMusicActive()) { 

            int mBackgroundStyle = Settings.System.getInt(mContext.getContentResolver(),
                    Settings.System.LOCKSCREEN_BACKGROUND_STYLE, 2);
            int mBackgroundColor = Settings.System.getInt(mContext.getContentResolver(),
                    Settings.System.LOCKSCREEN_BACKGROUND_COLOR, 0x00000000);
            switch (mBackgroundStyle) {
                case 0:
                    d = new ColorDrawable(mBackgroundColor);
                    d.setColorFilter(BACKGROUND_COLOR, PorterDuff.Mode.SRC_OVER);
                    mCustomBackground = d;
                    break;
                case 1:
                    KeyguardUpdateMonitor.getInstance(getContext()).dispatchSetBackground(null);
                    break;
                case 2:
                default:
                    mCustomBackground = d;
            }
            computeCustomBackgroundBounds(mCustomBackground);
            setBackground(mBackgroundDrawable);
        }

        if (!ActivityManager.isHighEndGfx()) {
            mCustomBackground = d;
            if (d != null) {
                d.setColorFilter(BACKGROUND_COLOR, PorterDuff.Mode.SRC_OVER);
            }
            computeCustomBackgroundBounds(mCustomBackground);
            invalidate();
        } else {
            if (getWidth() == 0 || getHeight() == 0) {
                d = null;
            }
            if (d == null) {
                mCustomBackground = null;
                setBackground(mBackgroundDrawable);
                return;
            }
            Drawable old = mCustomBackground;
            if (old == null) {
                old = new ColorDrawable(0);
                computeCustomBackgroundBounds(old);
            }

            d.setColorFilter(BACKGROUND_COLOR, PorterDuff.Mode.SRC_OVER);
            mCustomBackground = d;
            computeCustomBackgroundBounds(d);
            Bitmap b = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
            Canvas c = new Canvas(b);
            mBackgroundDrawable.draw(c);

            Drawable dd = new BitmapDrawable(b);

            mTransitionBackground = new TransitionDrawable(new Drawable[]{old, dd});
            mTransitionBackground.setCrossFadeEnabled(true);
            setBackground(mTransitionBackground);

            mTransitionBackground.startTransition(200);

            mCustomBackground = dd;
            invalidate();
        }

        if (d != null) {
            d.setColorFilter(BACKGROUND_COLOR, PorterDuff.Mode.SRC_OVER);
        }
        computeCustomBackgroundBounds(mCustomBackground);
        invalidate();
    }

这是我的 logcat 输出:

I/dalvikvm-heap(13100):强制收集软引用以分配 16571536 字节 E/dalvikvm-heap(13100):16571536 字节分配内存不足。 I/dalvikvm(13100):“主”prio=5 tid=1 RUNNABLE 我/dalvikvm(13100):| group="main" sCount=0 dsCount=0 obj=0x4159fe40 self=0x414d4548 我/dalvikvm(13100):| sysTid=13100 nice=0 sched=0/0 cgrp=apps 句柄=1074098536 我/dalvikvm(13100):| state=R schedstat=( 0 0 0 ) utm=877 stm=93 core=1 I/dalvikvm(13100):在 android.graphics.BitmapFactory.nativeDecodeStream(Native Method) I/dalvikvm(13100):在 android.graphics.BitmapFactory.decodeStreamInternal(BitmapFactory.java:613) I/dalvikvm(13100):在 android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:589) I/dalvikvm(13100): 在 android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:369) I/dalvikvm(13100): 在 android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:395) I/dalvikvm(13100):在 com.android.keyguard.KeyguardViewManager$1.onSetBackground(KeyguardViewManager.java:127) I/dalvikvm(13100):在 com.android.keyguard.KeyguardUpdateMonitor.dispatchSetBackground(KeyguardUpdateMonitor.java:452) I/dalvikvm(13100):在 com.android.keyguard.KeyguardViewManager$ViewManagerHost.setCustomBackground(KeyguardViewManager.java:302)

到目前为止,我尝试过的任何方法都没有奏效,有什么想法吗?

已编辑

进一步澄清这是在设置中设置图像的原因:

        } else if (requestCode == REQUEST_PICK_WALLPAPER) {
            FileOutputStream wallpaperStream = null;
            try {
                wallpaperStream = getActivity().openFileOutput(WALLPAPER_NAME,
                        Context.MODE_WORLD_READABLE);

            } catch (FileNotFoundException e) {
                return; // NOOOOO
            }
            Uri selectedImageUri = getLockscreenExternalUri();
            Bitmap bitmap;
            if (data != null) {
                Uri mUri = data.getData();
                try {
                    bitmap = MediaStore.Images.Media.getBitmap(getActivity().getContentResolver(),
                            mUri);
                    bitmap.compress(Bitmap.CompressFormat.PNG, 100, wallpaperStream);

                    Toast.makeText(getActivity(), getResources().getString(R.string.
                            background_result_successful), Toast.LENGTH_LONG).show();
                    Settings.System.putInt(getContentResolver(),
                            Settings.System.LOCKSCREEN_BACKGROUND_STYLE, 1);
                    updateVisiblePreferences();

                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            } else {
                try {
                    bitmap = BitmapFactory.decodeFile(selectedImageUri.getPath());
                    bitmap.compress(Bitmap.CompressFormat.PNG, 100, wallpaperStream);
                } catch (NullPointerException npe) {
                    Log.e(TAG, "SeletedImageUri was null.");
                    Toast.makeText(getActivity(), getResources().getString(R.string.
                            background_result_not_successful), Toast.LENGTH_LONG).show();
                    super.onActivityResult(requestCode, resultCode, data);
                    return;
                }
            }

        }

【问题讨论】:

  • 或许可以试试另一个更小的图片?
  • 问题在于它是从图库中选择的用户可选择图像,因此需要以某种方式压缩图像......如果普通图像可以设置自定义锁屏背景的选项相对无用'不被加载
  • 我不明白您为什么要尝试将图像压缩为 PNG,它在减少图像的内存占用方面没有任何作用,如果图像是图片,则生成的 PNG 文件将比原始 JPG 文件大很多。
  • 但主要问题是您试图分配一个占用 16MB 的位图,这意味着一个 4M 像素的图像。所以问题是屏幕是否能够以原始分辨率显示 4MPixel 图像。由于只有 Nexus 10 具有如此高分辨率,我会拒绝。如果您不想使用 3rd 方库,只需使用@Sharj 提供的第一个链接,那里的解决方案会将图像重新缩放到所需的大小。

标签: android image bitmap bitmapfactory


【解决方案1】:

您的内存不足是因为您没有仔细处理图像。请查看以下问题/答案,以更好地了解尝试加载图像时会发生什么:Strange out of memory issue while loading an image to a Bitmap object

如果您是新开发人员,那么我建议您只使用可以为您加载部分的任何好的库,否则将很难加载图像。

Android-Universal-Image-Loader:广泛使用的库https://github.com/nostra13/Android-Universal-Image-Loader

替代毕加索图书馆:一行代码为您完成工作:http://square.github.io/picasso/

更新:

位图占用大量内存,尤其是对于像这样的丰富图像 照片。例如,Galaxy Nexus 上的相机拍摄照片 高达 2592x1936 像素(5 兆像素)。如果位图配置 使用的是 ARGB_8888(从 Android 2.3 开始的默认值)然后 将此图像加载到内存中大约需要 19MB 内存(2592*1936*4 字节),立即耗尽某些设备上的每个应用程序的限制。

http://developer.android.com/training/displaying-bitmaps/index.html

【讨论】:

  • 我添加了我在设置中使用的代码来设置图像,以帮助阐明我如何处理图像
  • 可以使用公共布尔压缩(Bitmap.CompressFormat格式,int质量,OutputStream流)来压缩图像吗?
  • 问题不是功能问题是大小。您的设备内存不足。即使您优化了您的解决方案,也不能保证它可以在所有设备上运行。使用由顶级开发人员开发和使用的库是一个更好的选择。这只是一行代码。
  • 我同意,但我怀疑团队的其他成员是否会同意使用非谷歌代码进行这种考虑,因为在 4.4.2 之前,这完全一样的东西可以正常工作......但以上更新看起来给了我我需要的东西
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多