项目中有用到二维码扫描的功能,集成zbar后,一切看起来都挺好的,功能都好使,直到使用乐固进行了加固。
加固后的表现简直令人难受,扫描动画几乎停滞,整个界面卡的看起来和使用20kB的网速观看高清视频一样,点击按钮和返回键甚至都没反应或者过了很久才反应。很明显,主线程时间被大幅度占用了。
开始怀疑是加固方有问题,就换用了几个其他的加固方案,比如360加固,发现表现都差不多。然后直接联系乐固的客服,看他们能不能帮助解决。客服和工程师的态度都挺好的,中间各种巴拉巴拉找问题,尝试了好多次,可惜都没有发现问题在哪。
一个星期之后,我觉得靠他们没戏了,开始自己找原因(这里该反省一下,居然拖了一个星期才着手自己解决问题,当然也有乐固的态度太好了给我一种他们能解决问题的错觉o(╯□╰)o)。
最主要关注的地方是各个步骤的处理时间,Zbar和Zxing有一个不同的地方在于,Zxing使用的是多线程解析,图像解析并不会占用主线程时间,Zbar则没有这么做,怀疑Zbar的性能足够好,不需要开子线程。
通过打log的方式,发现PreviewCallback的回调中,执行一次解析的时间最多的一次足足超过了181ms(加固后),最短的一次也有130多ms,一秒钟可能会解析很多次,这样不卡才怪。
Zbar的回调中是按照这样的步骤来处理从相机拿到的数据的:
1.翻转相机的数据,因为android相机默认拿的横屏的数据。Zbar的CameraConfigurationManager中其实已经设置了竖屏预览(setDisplayOrientation(90)),但是这里从PreviewCallback中返回的数据依然是横屏的。相机返回的数据是一个byte数组(YUV格式),这个数组的长度是Camera的getPreviewSize()方法返回的尺寸的width*height*1.5,其中前面width*height存储像素点。
Zbar源码中这样翻转数据:
byte[] rotatedData = new byte[data.length];
for (int y = 0; y < size.height; y++) {
for (int x = 0; x < size.width; x++)
rotatedData[x * size.height + size.height - y - 1] = data[x
+ y * size.width];
}
// 宽高也要调整
int tmp = size.width;
size.width = size.height;
size.height = tmp;
2.初始化截取的矩形区域。扫码的话,并不需要解析整个图片,而是二维码所在的区域,这里是生成二维码取景框的区域。
3.使用Zbar进行图像解析。
这里主要的耗时发生在第一步和第三步上面。第三步的话最终调用的Native方法,不太好改,所以优化主要集中在第一步上面。
对于第一步的处理是这样考虑的:扫码的话,不在乎是横屏还是竖屏,所以这里没有必要翻转数据,第一步的时间开销其实是没有必要的。这里的重点是不翻转数据了,那么需要处理的图像数据范围就从原来的竖屏变成了横屏,方法如下:
Rect convertCrop(Rect src) {
int cameraHeight = mCameraManager.getCameraResolution().y;
Rect rect = new Rect();
rect.left = src.top;
rect.right = rect.left + src.height();
rect.top = cameraHeight - (src.left + src.width());
rect.bottom = rect.top + src.width();
return rect;
}
处理完之后,再使用乐固进行加固,果然不在卡顿了,谢天谢地。