有很多同学找我,都是关于界面卡顿的问题,问我能不能帮忙解决下。由于性能优化涉及的知识点比较多,我一时半会也无法彻底回答。恰好之前在做需求时也遇到了一个卡顿的问题,因此今天写下这篇卡顿优化的文章,希望对大家有所帮助。先来看看卡顿的现象:
1. 查找卡顿原因
从上面的现象来看,应该是主线程执行了耗时操作引起了卡顿,因为正常滑动是没问题的,只有在刷新数据的时候才会出现卡顿。至于什么情况下会引起卡顿,之前在自定义 View 部分已有详细讲过,这里就不在啰嗦。我们猜想可能是耗时引起的卡顿,但也不能 100% 确定,况且我们也并不知道是哪个方法引起的,因此我们只能借助一些常用工具来分析分析,我们打开 Android Device Monitor 。
2. RxJava 线程切换
我们找到了是高斯模糊处理耗时导致了界面卡顿,那现在我们把高斯模糊算法处理放入子线程中去,处理完后再次切换到主线程,这里采用 RxJava 来实现。
Observable.just(resource.getBitmap())
.map(bitmap -> {
// 高斯模糊
Bitmap blurBitmap = ImageUtil.doBlur(resource.getBitmap(), 100, false);
blurBitmapCache.put(path, blurBitmap);
return blurBitmap;
}).subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(blurBitmap -> {
if (blurBitmap != null) {
recommendBgIv.setImageBitmap(blurBitmap);
}
});
2. 高斯模糊算法分析
把耗时操作放到子线程中去处理,的确解决了界面卡顿问题。但这其实是治标不治本,我们发现图片加载处理异常缓慢,内存久高不下有时可能会导致内存溢出。接下来我们来分析一下高斯模糊的算法实现:
看上面这几张图,我们通过怎样的操作才能把第一张图处理成下面这两张图?其实就是模糊化,怎么才能做到模糊化?我们来看下高斯模糊算法的处理过程。再上两张图:
所谓"模糊",可以理解成每一个像素都取周边像素的平均值。上图中,2是中间点,周边点都是1。“中间点"取"周围点"的平均值,就会变成1。在数值上,这是一种"平滑化”。在图形上,就相当于产生"模糊"效果,"中间点"失去细节。
为了得到不同的模糊效果,高斯模糊引入了权重的概念。上面分别是原图、模糊半径3像素、模糊半径10像素的效果。模糊半径越大,图像就越模糊。从数值角度看,就是数值越平滑。接下来的问题就是,既然每个点都要取周边像素的平均值,那么应该如何分配权重呢?如果使用简单平均,显然不是很合理,因为图像都是连续的,越靠近的点关系越密切,越远离的点关系越疏远。因此,加权平均更合理,距离越近的点权重越大,距离越远的点权重越小。对于这种处理思想,很显然正太分布函数刚好满足我们的需求。但图片是二维的,因此我们需要根据一维的正太分布函数,推导出二维的正太分布函数:
if (rad