Android BitmapFactory.decodeResource和无法解释的内存不足

Android BitmapFactory.decodeResource和无法解释的内存不足,android,android-image,android-bitmap,bitmapfactory,android-memory,Android,Android Image,Android Bitmap,Bitmapfactory,Android Memory,我在解码可绘制图像资源960x926px jpg时遇到了一个奇怪的内存不足错误,分配了3555856字节。 图像仅放置在可绘制的xxhdpi(3x)中,我使用的是hdpi(1.5x)设备。 两个问题: 为什么我在堆中有足够的空闲内存时会出错 hdpi设备的分配应为((960/2)x(926/2))x 4=888960字节(不是3555856字节) 有人能给我解释一下吗 注意:问题是为什么要为3.5MB分配一个OOM,而有22.5MB的可用内存(请参阅日志) 03-18 17:30:15.05

我在解码可绘制图像资源960x926px jpg时遇到了一个奇怪的内存不足错误,分配了3555856字节。 图像仅放置在可绘制的xxhdpi(3x)中,我使用的是hdpi(1.5x)设备。 两个问题:


  • 为什么我在堆中有足够的空闲内存时会出错

  • hdpi设备的分配应为((960/2)x(926/2))x 4=888960字节(不是3555856字节)

有人能给我解释一下吗

注意:问题是为什么要为3.5MB分配一个OOM,而有22.5MB的可用内存(请参阅日志)

03-18 17:30:15.050 32750-32750/?D/dalvikvm:GC\u FOR\u ALLOC freed 10809K,49%空闲23735K/46087K,暂停89毫秒,总计89毫秒

03-18 17:30:15.050 32750-32750/?I/VM堆:强制收集 3555856字节分配的软参考

03-18 17:30:15.160 32750-32750/?D/dalvikvm:29K前的总承包商, 49%免费23705K/46087K,暂停103ms,总计103ms

03-18 17:30:15.160 32750-32750/?E/dalvikvm堆:上的内存不足 3555856字节分配

03-18 17:30:15.160 32750-32750/?I/dalvikvm:“主”优先级=5 tid=1 可运行

03-18 17:30:15.160 32750-32750/?I/dalvikvm:| group=“main”scont=0 dsCount=0 obj=0x418fc6a0 self=0x401C008

03-18 17:30:15.160 32750-32750/?I/dalvikvm:| sysTid=32750 nice=1 sched=0/0 cgrp=apps handle=1075251280

03-18 17:30:15.160 32750-32750/?I/dalvikvm:| schedstat=(0) utm=3807 stm=859芯=0

03-18 17:30:15.160 32750-32750/?I/dalvikvm:在 android.graphics.BitmapFactory.nativeDecodeAsset(本机方法)

03-18 17:30:15.160 32750-32750/?I/dalvikvm:在 android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:636)

03-18 17:30:15.160 32750-32750/?I/dalvikvm:在 decodeResourceStream(BitmapFactory.java:484) 03-18 17:30:15.160 32750-32750/? I/dalvikvm:在 decodeResource(BitmapFactory.java:512)

03-18 17:30:15.160 32750-32750/?I/dalvikvm:在 decodeResource(BitmapFactory.java:542)

1) 如果hdpi文件夹中没有较小的版本,它将使用最接近的匹配项。因此,如果不存在hdpi或drawable/版本,它将使用xxhdpi

2) 它不会自动缩放。它将以全尺寸显示


3) 如果这导致OOM,则通常可能使用了太多内存。

获得OOM的原因是,当图像解码到内存中时,其位图的大小大于图像分辨率(几乎是我不确定该值的4倍)

在处理图像时需要记住的几点:

  • 永远不要在主线程上处理位图。在后台执行所有解码
  • 总是考虑屏幕大小或要放置图像的视图的大小。例如,如果屏幕大小为360X720(一些随机值),则解码分辨率大于所需大小的全分辨率图像不是一个好主意(因为它将在主内存中加载完整的位图)。所以解码时一定要进行采样 因此,请尝试使用以下解决方案:

    步骤1:查找屏幕大小

    Glide.with (context).load (path).asBitmap().into(imageView);
    
    取自

    步骤1:创建一个异步任务来解码位图

    如果使用异步任务作为内部类,则考虑使用公共静态内部类(保存内存泄漏问题),并保持图像加载的IVIEVIEW的弱引用。还可以将要解码的图像资源、文件或流传递给构造函数。在下面的代码中,假设您想要解码资源。还包括步骤1中计算的焊道宽度和高度

    public static class BitmapDecodeTask extends AsyncTask<Void, Void, Bitmap> {
        //the reason to use a weak reference is to protect from memory leak issues.
        private WeakReference<Context> mContextReference;
        private WeakReference<ImageView> mImageViewReference;
        private int mResourceId;
        private int mRequiredWidth;
        private int mRequiredHeight;
    
        public BitmapDecodeTask(Context context, ImageView imageView, int resourceId, int width, int height) {
            this.mContextReference = new WeakReference<>(context);
            this.mImageViewReference = new WeakReference<>(imageView);
            this.mResourceId = resourceId;
            this.mRequiredWidth = width;
            this.mRequiredHeight = height;
        }
    
        @Override
        protected Bitmap doInBackground(Void... params) {
    
            Context context = mContextReference.get();
    
            if(context != null) {
                BitmapFactory.Options options = new BitmapFactory.Options();
                options.inJustDecodeBounds = true;
                BitmapFactory.decodeResource(getResources(), mImageResourceId, options);
    
                //set inSampleSize
                options.inSampleSize = calculateInSampleSize(options);
    
                //set inJustDecodeBounds = false;
                options.inJustDecodeBounds = false;
    
                //decode
                return BitmapFactory.decodeResource(getResources(), mImageResourceId, options);
            }
    
            return null;
        }
    
        @Override
        protected void onPostExecute(Bitmap bitmap) {
            //check if imageview is available or not
            ImageView imageView = mImageViewReference.get();
    
            if(imageView != null && bitmap != null) {
                imageView.setImageBitmap(bitmap);
            }
        }
    
        public static int calculateInSampleSize(BitmapFactory.Options options) {
            // Raw height and width of image
            final int height = options.outHeight;
            final int width = options.outWidth;
            int inSampleSize = 1;
    
            if (height > mRequiredHeight || width > mRequiredWidth) {
                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) > mRequiredHeight 
                    && (halfWidth / inSampleSize) > reqWidth) {
                    inSampleSize *= 2;
                }
            }
            return inSampleSize;
        }
    }
    
    公共静态类BitmapDecodeTask扩展了AsyncTask{
    //使用弱引用的原因是为了防止内存泄漏问题。
    私人财富参照;
    私有WeakReference mImageViewReference;
    私有资源;
    私有整数mRequiredWidth;
    私人内部要求的高度;
    公共位图解码任务(上下文上下文、ImageView、ImageView、int resourceId、int width、int height){
    this.mContextReference=新的WeakReference(上下文);
    this.mImageViewReference=新的WeakReference(imageView);
    this.mResourceId=资源ID;
    this.mRequiredWidth=宽度;
    this.mRequiredHeight=高度;
    }
    @凌驾
    受保护位图doInBackground(无效…参数){
    Context=mContextReference.get();
    if(上下文!=null){
    BitmapFactory.Options=new-BitmapFactory.Options();
    options.inJustDecodeBounds=true;
    decodeResource(getResources(),mImageResourceId,选项);
    //设置样本大小
    options.inSampleSize=计算样本大小(选项);
    //设置inJustDecodeBounds=false;
    options.inJustDecodeBounds=false;
    //解码
    返回BitmapFactory.decodeResource(getResources(),mImageResourceId,options);
    }
    返回null;
    }
    @凌驾
    受保护的void onPostExecute(位图){
    //检查imageview是否可用
    ImageView=mImageViewReference.get();
    if(imageView!=null&&bitmap!=null){
    设置图像位图(位图);
    }
    }
    公共静态int-calculateInSampleSize(BitmapFactory.Options选项){
    //图像的原始高度和宽度
    最终内部高度=options.outHeight;
    最终整数宽度=options.outWidth;
    int inSampleSize=1;
    如果(高度>mRequiredHeight | |宽度>mRequiredWidth){
    最终int半高=高度/2;
    最终整数半宽度=宽度/2;
    //计算样本大小中的最大值
    
    @Override
     public void onDestroy() {
        yourbitmap.recycle();
        yourbitmap = null;
        super.onDestroy();
     }
    
    compile 'com.github.bumptech.glide:glide:3.5.2'
    
    Glide.with (context).load (path).asBitmap().into(imageView);