ViewPager里Bitmap主动回收资源的另一种思路
原创文章,欢迎转载,转载请注明: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左右内存,如下图所示:
但是有一点要注意,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