【问题标题】:OutOfMemory error while applying wallpaper应用壁纸时出现 OutOfMemory 错误
【发布时间】:2015-12-09 15:12:25
【问题描述】:

我在尝试将壁纸应用到设备时遇到 OutOfMemoryError。

我正在使用 AsyncTask,有时它可以正常工作,但有时会发生这种情况。

有人可以帮我进一步优化它吗?提前致谢。

AsyncTask 代码:

public class ApplyWallpaper extends AsyncTask<Void, String, Boolean> {
    private Context context;
    private Activity activity;
    private MaterialDialog dialog;
    private Bitmap resource;
    private View layout;
    private boolean isPicker;
    private Snackbar snackbar;

    public ApplyWallpaper(Context context, MaterialDialog dialog, Bitmap resource, Boolean isPicker, View layout) {
        this.activity = (Activity) context;
        this.context = context;
        this.dialog = dialog;
        this.resource = resource;
        this.isPicker = isPicker;
        this.layout = layout;
    }

    @Override
    protected Boolean doInBackground(Void... params) {
        WallpaperManager wm = WallpaperManager.getInstance(context);
        Boolean worked;
        try {
            wm.setBitmap(scaleToActualAspectRatio(resource));
            worked = true;
        } catch (IOException e2) {
            worked = false;
        }
        return worked;
    }

    @Override
    protected void onPostExecute(Boolean worked) {
        if (worked) {
            dialog.dismiss();
            Util.showSimpleSnackbar(layout,
                    context.getString(R.string.set_as_wall_done), 1);
        } else {
            String retry = context.getResources().getString(R.string.retry);
            snackbar = Snackbar
                    .make(layout, R.string.error, Snackbar.LENGTH_INDEFINITE)
                    .setAction(retry.toUpperCase(), new View.OnClickListener() {
                        @Override
                        public void onClick(View view) {
                            new ApplyWallpaper(context, dialog, resource, isPicker, layout);
                        }
                    });
            snackbar.setActionTextColor(context.getResources().getColor(R.color.accent));
            snackbar.show();
        }
        if (isPicker) {
            activity.finish();
        }

    }

    public Bitmap scaleToActualAspectRatio(Bitmap bitmap) {
        if (bitmap != null) {
            boolean flag = true;
            int deviceWidth = activity.getWindowManager().getDefaultDisplay()
                    .getWidth();
            int deviceHeight = activity.getWindowManager().getDefaultDisplay()
                    .getHeight();
            int bitmapHeight = bitmap.getHeight();
            int bitmapWidth = bitmap.getWidth();
            if (bitmapWidth > deviceWidth) {
                flag = false;
                int scaledHeight = deviceHeight;
                int scaledWidth = (scaledHeight * bitmapWidth) / bitmapHeight;
                try {
                    if (scaledHeight > deviceHeight)
                        scaledHeight = deviceHeight;
                    bitmap = Bitmap.createScaledBitmap(bitmap, scaledWidth,
                            scaledHeight, true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            if (flag) {
                if (bitmapHeight > deviceHeight) {
                    int scaledHeight = deviceHeight;
                    int scaledWidth = (scaledHeight * bitmapWidth)
                            / bitmapHeight;
                    try {
                        if (scaledWidth > deviceWidth)
                            scaledWidth = deviceWidth;
                        bitmap = Bitmap.createScaledBitmap(bitmap, scaledWidth,
                                scaledHeight, true);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        return bitmap;
    }

}

壁纸资源加载自:

Glide.with(context)
.load(linkForWallpaper)
.asBitmap()
.into(new SimpleTarget<Bitmap>() {
    @Override
    public void onResourceReady(final Bitmap resource, GlideAnimation<? super Bitmap> glideAnimation) {
        if (resource != null) {
            new ApplyWallpaper(context, dialogApply, resource,
                    false, layout, fab).execute();
        }
    }
});

【问题讨论】:

  • 位图资源从何而来?
  • @tinysunlight 问题已编辑
  • 使用 Android Studio 应用监控工具分析应用在应用壁纸时所使用的堆内存,并找出哪些对象正在填满堆
  • resource.recycle() ; resource = null after bitmap = Bitmap.createScaledBitmap(bitmap, scaledWidth, scaledHeight, true);并在使用Glide加载图片时设置小尺寸。

标签: android android-asynctask out-of-memory wallpaper android-wallpaper


【解决方案1】:

在 Manifest 文件中的应用程序标签中添加 android:largeHeap="true"

<application
        android:name=".MyApplication"
        android:largeHeap="true"
        ........ >
</application>

它会增加为您的应用分配的内存

官方文件是怎么说的:

android:largeHeap

您的应用程序的进程是否应该使用大型 达尔维克堆。这适用于为 应用。它仅适用于第一个加载到 过程;如果您使用共享用户 ID 来允许多个 应用程序使用一个进程,他们都必须使用这个选项 始终如一,否则他们将产生不可预测的结果。大多数应用程序应该 不需要这个,而是应该专注于减少他们的整体 内存使用以提高性能。启用此功能也不会 保证可用内存的固定增加,因为某些设备 受到总可用内存的限制。

要在运行时查询可用内存大小,请使用方法 getMemoryClass()getLargeMemoryClass()

【讨论】:

    【解决方案2】:

    您正在加载的位图的原始大小是多少?我自己也遇到了同样的问题,我能够解决它的唯一方法是首先将其调整为比原来小得多的大小,然后加载它(我使用毕加索)将其缩小并将其设置为图像视图。

    【讨论】:

      【解决方案3】:

      你在 scale...() 方法中一次解码和解析位图,这是非常有任务的,内存方面的,你抓住它然后再做一次而不调用它,它会因为明显缺乏缩放而消失

      使用巨大位图进行缩放的关键是在墙纸管理器中进行设置之前,可能手动进行解析和缩放。零碎的工作是帆布。 android.graphics.Canvas 如果我没记错的话。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-08-28
        • 2011-10-21
        • 1970-01-01
        • 2012-02-11
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多