欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

ViewPager里Bitmap主动回收资源的另一种思路

程序员文章站 2024-03-24 15:39:40
...

原创文章,欢迎转载,转载请注明:fishcode.cn
作者:JaydenZhou

  Android是个资源吃紧的系统,虽然现在的手机运存越来越大,但是由于手机屏幕越来越大,加载的图片越来越大,加载后换算成内存占用也就越来越大,特别是用Bitmap直接不做任何压缩处理就加载显示的话,占用更大。因此我要分享其中的一种场景,我们可以主动去释放掉Bitmap资源,从而减轻内存占用。

场景:启动轮播图加载和释放优化

1.采用ViewPager + 多张图片来展示,加载数据的Adapter用继承于PagerAdapter的StaticPagerAdapter,类似参考FragmentStatePagerAdapter,是为了将所有要看的图片都加载到内存里面,这样用户左右滑动起来,就不会再触发初始化和销毁,这样就感觉很流畅,缺点就是占用内存大。
2.若采用类似FragmentPagerAdapter的话,就会默认销毁索引间距超过1的对象,这样内存不会占用过大,但是由于重复初始化,会造成低端手机滑动卡顿。
3.为了保持数据一致,所有图片加载显示时候都没有经过压缩处理。

传统的解决方法:

  在PagerAdapter里面复写 destroyItem 方法,然后主动回收图片:

public void releaseImageViewResouce(ImageView imageView) {  
    if (imageView == null) return;  
    Drawable drawable = imageView.getDrawable();  
    if (drawable != null && drawable instanceof BitmapDrawable) {  
        BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;  
        Bitmap bitmap = bitmapDrawable.getBitmap();  
        if (bitmap != null && !bitmap.isRecycled()) {  
            bitmap.recycle();  
            bitmap=null;  
        }  
    }  
    System.gc();  
}

但是缺点也就是跟用FragmentPagerAdapter的一样,用户重新左滑回来的话,就又会出现重新初始化卡顿的情况。

新的解决方法:

  原则是我们需要保证滑动时候的顺畅,以及不需要的时候及时回收。所以在PagerAdapter相关继承类里面写一个方法,然后当不需要展示时候,从外部调用,进行整体的释放。

/**
  * 手动释放轮播引导图资源,不然内存会过非常久才可能会被gc回收
  * 从图像类里面获取,其中mViewList是静态Adapter里面存储的View集合。
  * */
 public void releaseAllImageRes() {
   for(View view : mViewList) {
       if(view instanceof ImageView) {
           ImageView imageView = (ImageView)view;
           imageView.setImageBitmap(null);
           BitmapUtil.releaseImageViewResouce(imageView);
         }
     }
 }
    /**
     * 释放图片资源
     * @param imageView
     */
    public static void releaseImageViewResouce(ImageView imageView) {
        if (imageView == null) return;
        Drawable drawable = imageView.getDrawable();
        if (drawable != null && drawable instanceof BitmapDrawable) {
            BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
            Bitmap bitmap = bitmapDrawable.getBitmap();
            if (bitmap != null && !bitmap.isRecycled()) {
                bitmap.recycle();
                bitmap=null;
            }
        }
        System.gc();
    }

  如此这样一来,我们可以主动触发recycle和gc,这样据我实测,1080P手机下的5张引导图,主动回收的话可以回收掉60M左右内存,如下图所示:
ViewPager里Bitmap主动回收资源的另一种思路
ViewPager里Bitmap主动回收资源的另一种思路

  但是有一点要注意,recycle这个不能随便用,你得确认后续app内不会再用这个资源时候才能主动这么调用,否则有可能出现你要再次使用的时候,报错。如源码里面的解释:

/**
 * Free the native object associated with this bitmap, and clear the
 * reference to the pixel data. This will not free the pixel data synchronously;
 * it simply allows it to be garbage collected if there are no other references.
 * The bitmap is marked as "dead", meaning it will throw an exception if
 * getPixels() or setPixels() is called, and will draw nothing. This operation
 * cannot be reversed, so it should only be called if you are sure there are no
 * further uses for the bitmap. This is an advanced call, and normally need
 * not be called, since the normal GC process will free up this memory when
 * there are no more references to this bitmap.
 */

参考文章:http://blog.csdn.net/bobxie520/article/details/51167957