ImageView.setImageResource(resId) OOM和滑动卡顿,问题的解决!

最近一些用户的老手机 出现加载引导页的时候,滑动界面卡顿和OOM闪退的问题
Failed to allocate a 74649612 byte allocation with 16777216 free bytes and 70MB until OOM

com.wcyq.gangrong.ui.activity.NewGuideActivity$GuidPagerAdapter.instantiateItem(NewGuideActivity.java:105)

之前测试公司的测试机测试一直也没有出现这种问题.

通过bugly 捕捉到了这个错误;

市面上的解决办法,我所知道的有两种:

  第一种,弃用  

imageView.setImageResource(resId)

采用图片加载框架进行加载,解决内存溢出和卡顿问题:

代码如下:

Glide.with(mContext).load(resId).placeholder(resId).diskCacheStrategy(DiskCacheStrategy.RESULT).into(imageView);

或者:

   app.imageLoader.displayImage(
                    imageUrls.get(i), imageView, Utils.setImageLoaderImg(R.drawable.pic_launchpage_fail,R.drawable.pic_launchpage,0));

第二种方式: 自己对图片先进行网络在线压缩,第二把png转化为jpg,同样的图片 png 要比jpg的大很多

  然后,自行对设置图片格式RGB-565

   然后隔行取点,  减少内存中的图片大小

如下:

@Override
    protected void onStop() {
        super.onStop();
        if (btp!=null){
            btp.recycle();
        }

    }

    /**
     * 大图片处理机制
     * 利用Bitmap 转存 R图片
     */
    public static Bitmap btp;

    public void getBitmapForImgResourse(Context mContext, int imgId, ImageView mImageView) throws IOException {
        InputStream is = mContext.getResources().openRawResource(imgId);
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = false;
        options.inPreferredConfig = Bitmap.Config.RGB_565;
        options.inPurgeable = true;
        options.inInputShareable = true;
        options.inSampleSize = 1;
        btp = BitmapFactory.decodeStream(is, null, options);
        mImageView.setImageBitmap(btp);
        //    btp.recycle();
        is.close();
    }

备注:

  那是为什么,会导致oom呢:

         原来当使用像 imageView.setBackgroundResource,imageView.setImageResource, 或者 BitmapFactory.decodeResource  这样的方法来设置一张大图片的时候,

         这些函数在完成decode后,最终都是通过java层的createBitmap来完成的,需要消耗更多内存。

         因此,改用先通过BitmapFactory.decodeStream方法,创建出一个bitmap,再将其设为ImageView的 source,decodeStream最大的秘密在于其直接调用JNI>>nativeDecodeAsset()来完成decode,无需再使用java层的createBitmap,从而节省了java层的空间。如果在读取时加上图片的Config参数,可以跟有效减少加载的内存,从而跟有效阻止抛out of Memory异常。

        另外,需要特别注意: 

         decodeStream是直接读取图片资料的字节码了, 不会根据机器的各种分辨率来自动适应,使用了decodeStream之后,需要在hdpi和mdpi,ldpi中配置相应的图片资源,否则在不同分辨率机器上都是同样大小(像素点数量),显示出来的大小就不对了。

 延伸:

options.inSampleSize = 2;的意思是什么

这个是读取bitmap时用到的属性,是为了对原图降采样.

比如原图是一个 4000 * 4000 点阵的图,占用内存就是  4000 * 4000 * 单个像素占用字节数 
单个像素占用字节数取决于你用的是 RGB565, ARGB8888 等. 4000 * 4000 这个解析度已很接近目前市面主流机器的默认照片解析度.
假设你用的是RGB565解析这张图,那一个点就占用2个字节.如果完整解析这个图片,就需要 大约3.2MB的内存.
如果你用了一个GridView,同时显示了30张这种图,那几乎可以确定你会收到一个OOM异常.

所以需要对这种大图进行降采样,以减小内存占用.毕竟拇指大小的地方根本用不着显示那么高的解析度.
因为直接从点阵中隔行抽取最有效率,所以为了兼顾效率, inSampleSize 这个属性只认2的整数倍为有效.
比如你将 inSampleSize 赋值为2,那就是每隔2行采1行,每隔2列采一列,那你解析出的图片就是原图大小的1/4.
这个值也可以填写非2的倍数,非2的倍数会被四舍五入.

综上,用这个参数解析bitmap就是为了减少内存占用.
  

你可能感兴趣的:(安卓Bug,安卓)