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中配置相应的图片资源,否则在不同分辨率机器上都是同样大小(像素点数量),显示出来的大小就不对了。
 */

延伸:

这个是读取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就是为了减少内存占用.

阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页