【问题标题】:Loading Bitmaps efficiently - still getting out of memory error有效加载位图 - 仍然出现内存不足错误
【发布时间】:2016-11-03 16:38:25
【问题描述】:

加载自定义图像时出现内存不足错误。我阅读了https://developer.android.com/training/displaying-bitmaps/load-bitmap.html 寻求帮助。

我正在按照示例对流进行解码以首先获取大小信息,然后再进行解码。仍然在第一次解码时崩溃。有没有办法解决这个问题?

ava.lang.OutOfMemoryError:无法分配 48771084 字节分配,其中 16776928 个可用字节和 25MB 直到 OOM BackgroundImageManager.java,第 84 行

dalvik.system.VMRuntime.newNonMovableArray 原生方法 2 android.graphics.BitmapFactory.nativeDecodeStream 原生方法 3 android.graphics.BitmapFactory.decodeStreamInternal BitmapFactory.java,第 882 行 4 android.graphics.BitmapFactory.decodeStream BitmapFactory.java,第 858 行 5 android.graphics.BitmapFactory.decodeStream BitmapFactory.java,第 896 行 6 com.myapp.Utils.BackgroundImageManager.background BackgroundImageManager.java,第 8 行

public class BackgroundImageManager {
    private final static String TAG = BackgroundImageManager.class.getSimpleName();
    private static InputStream currentBackgroundImage;

    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;
            }
        }
        Log.v("Biscuit-Sample", String.valueOf(inSampleSize));
        if (inSampleSize < 4) {
            inSampleSize = 4;
        }
        return inSampleSize;
    }

    public static Drawable background(Context context, Store store) {
        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);

        String bgUri = null;
        int bgId = 0;
        if (store != null) {
            bgUri = store.backgroundImageURI;
            bgId = store.backgroundImageNumber;
        }

        if (currentBackgroundImage != null) {
            try {
                currentBackgroundImage.close();
                Log.v(TAG, "Current background image closed.");
            } catch (IOException e) {
                Log.e(TAG, "Could not close background image.", e);
            }
        }

        if(bgUri != null && !bgUri.isEmpty()) {
            try {
                BitmapFactory.Options options = new BitmapFactory.Options();
                options.inJustDecodeBounds = true;

                Activity activity = (Activity) context;
                Display display = activity.getWindowManager().getDefaultDisplay();
                Point size = new Point();
                display.getSize(size);
                int width = size.x;
                int height = size.y;
                BitmapFactory.decodeStream( context.getContentResolver().openInputStream(Uri.parse(bgUri)) );
                options.inSampleSize = BackgroundImageManager.calculateInSampleSize(options, width, height);
                Bitmap bitmap = BitmapFactory.decodeStream( context.getContentResolver().openInputStream(Uri.parse(bgUri)) );
                Drawable d = new BitmapDrawable(context.getResources(), bitmap);
                return d;
            } catch (FileNotFoundException e) {
                Log.e(TAG, "Custom background image file could not be found.", e);
            } catch (IOException e) {
                Log.e(TAG, "Could not close custom background image after creating drawable", e);
            }
        }
        if(bgId != 0) {
            try {
                return context.getResources().getDrawable(bgId);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return context.getResources().getDrawable(R.drawable.bg_default);
    }

【问题讨论】:

    标签: java android bitmap


    【解决方案1】:

    要处理 bitmpas,您可以使用众多可用的开源库之一。例如Fresco

    你的问题:

    首先,您将同一个位图解码两次。

    BitmapFactory.decodeStream( context.getContentResolver().openInputStream(Uri.parse(bgUri)) );
    options.inSampleSize = BackgroundImageManager.calculateInSampleSize(options, width, height);
    Bitmap bitmap = BitmapFactory.decodeStream( context.getContentResolver().openInputStream(Uri.parse(bgUri)) );
    

    这可能是错误的复制/粘贴。在第一行中,位图被解码并且未被使用。删除第一个BitmapFactory.decodeStream

    问题出在这里

    Bitmap bitmap = BitmapFactory.decodeStream( context.getContentResolver().openInputStream(Uri.parse(bgUri)) );
    

    应该是

    Bitmap bitmap = BitmapFactory.decodeStream( context.getContentResolver().openInputStream(Uri.parse(bgUri)), null, options);
    

    选项的对象必须是方法调用的一部分才能使用。

    【讨论】:

      【解决方案2】:

      更好的图像管理方法是使用 Picasso 库,因为它管理缓存和内存,因此可以避免 OutOfMemory 崩溃。

      示例:Picasso.with(Context).load("your_url").into(yourImageView);

      更多信息在这里: Picasso library

      【讨论】:

      • @an_android_dev 我是否必须打开一个输入流,或者我可以使用 Uri.parse(bgUri) 代替“your_url”吗?
      • @quantumpotato 你可以使用 url 字符串。例如:load("example.com/myimage.jpeg");
      • @an_android_dev 我会试试这个。我拥有的 URI 是设备本地的
      猜你喜欢
      • 2012-12-30
      • 1970-01-01
      • 2016-01-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多