android基础知识Android性能「性能优化」

「性能优化4.0」运行期间检测不合理的图片

2019-04-20  本文已影响18人  未见哥哥

Bitmap 内存模型

如何计算 bitmap 占用内存

  1. getRowBytes:Since API Level 1
  2. getByteCount:Since API Level 12
  3. getAllocationByteCount:Since API Level 19
public static int getBitmapSize(Bitmap bitmap) {  
     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {  //API 19  
         return bitmap.getAllocationByteCount();  
     }  
     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1) { //Since API 12  
         return bitmap.getByteCount();  
     }  

     return bitmap.getRowBytes() * bitmap.getHeight();               
 } 
getAllocationByteCount

size= width x height x (一个像素占用内存) x 压缩比例

检测不合理图片

在实际开发中,如果服务传给客户端的图片的实际宽高是远大于 ImageView 的宽高,那么这种情况是会浪费内存,那么如何去检测这种不合理的情况呢?

通用方式

给每一个 ImageView 设置一个 PreDrawListener ,在回调中计算 Bitmap 的大小和 ImageView 的大小。

这种方案是可以实现检测功能,但是缺点也很明显,不通用,侵入性比较大。

Hook 方式

Hook 意思就是挂钩,钩住原有方法,修改执行逻辑,这种 Hook 方法是在运行时插桩。

下面介绍一个 Hook 框架 :Epic

该框架 Hook 的最小粒度为方法层面,该框架支持 4.0-9.0 机型

引入epic框架

compile 'me.weishu:epic:0.3.6'

使用 epic 来检测不合理图片

public void setImageBitmap(Bitmap bm) {
    ...
}
DexposedBridge.findAndHookMethod(ImageView.class, "setImageBitmap", Bitmap.class, new XC_MethodHook() {
    @Override
    protected void afterHookedMethod(MethodHookParam param) throws Throwable {
        super.afterHookedMethod(param);
        if (param.thisObject instanceof ImageView) {
            final ImageView imageView = (ImageView) param.thisObject;
            if (imageView.getDrawable() instanceof BitmapDrawable) {
                BitmapDrawable drawable = (BitmapDrawable) imageView.getDrawable();
                final Bitmap bitmap = drawable.getBitmap();
                if (bitmap != null) {
                    //bitmap 宽高
                    int bitmapWidth = bitmap.getWidth();
                    int bitmapHeight = bitmap.getHeight();
                    //视图宽高
                    int viewWidth = imageView.getWidth();
                    int viewHeight = imageView.getHeight();
                    if (viewHeight > 0 && viewWidth > 0) {//view 有宽高
                        //当图片宽高都大于视图宽高的2倍时就报出警告
                        if (bitmapWidth >= viewWidth << 2 && bitmapHeight >= viewHeight << 2) {
                            warn(bitmapWidth, bitmapHeight, viewWidth, viewHeight);
                        }
                    } else {
                        imageView.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
                            @Override
                            public boolean onPreDraw() {
                                int bitmapWidth = bitmap.getWidth();
                                int bitmapHeight = bitmap.getHeight();
                                int viewWidth = imageView.getWidth();
                                int viewHeight = imageView.getHeight();
                                if (bitmapWidth >= viewWidth << 2 && bitmapHeight >= viewHeight << 2) {
                                    warn(bitmapWidth, bitmapHeight, viewWidth, viewHeight);
                                }
                                imageView.getViewTreeObserver().removeOnPreDrawListener(this);
                                return true;
                            }
                        });
                    }
                }
            }
        }
    }
});
private void warn(int bitmapWidth, int bitmapHeight, int viewWidth, int viewHeight) {
    StringBuffer msg = new StringBuffer();
    msg.append("图片大小不合理:")
            .append("bitmapWidth=").append(bitmapWidth)
            .append(",bitmapHeight=").append(bitmapHeight)
            .append(",viewWidth=").append(viewWidth)
            .append(",viewHeight=").append(viewHeight);
    //不合理
    Log.e(TAG, Log.getStackTraceString(new Throwable(msg.toString())));
}
log

总结

本文使用的介绍了两种方式来检测不合理图片:

通用的方法:

而 hook 的方式的优缺点如下::

参考

本文是笔者学习之后的总结,方便日后查看学习,有任何不对的地方请指正。

记录于 2019年4月16号

上一篇 下一篇

猜你喜欢

热点阅读