一、主页面布局优化
应用主界面布局优化是老生常谈了,综合起来无非就是下面两点,这个需要结合具体的界面布局去做优化,网上也有比较多的资料可以查阅
- 通过减少冗余或者嵌套布局来降低视图层次结构
- 用 ViewStub 替代在启动过程中不需要显示的 UI 控件
viewstub就是动态加载试图;也就是在我们的app启动绘制页面的时候,他不会绘制到view树中;当在代码中执行inflate操作后,她才会被添加到试图中。其实ViewStub就是一个宽高都为0的一个View,它默认是不可见的,只有通过调用setVisibility函数或者Inflate函数才 会将其要装载的目标布局给加载出来,从而达到延迟加载的效果,这个要被加载的布局通过android:layout属性来设置。最终目的是把app加载页面的速度提高了,使用户体验更好. - 使用自定义 View 替代复杂的 View 叠加
二、闲时调用
在应用启动的时候,为了加快启动速度,往往需要把一些比较重的操作放到子线程中,或者是延时加载。将任务放在子线程中是一个比较简单并且看起来有效的操作,但是呢,也不能太过于依赖子线程,它虽然不会阻塞主线程,但是却会跟主线程抢占CPU,当子线程很多并且任务很重的时候,也还是会拖慢主线程的,不信你可以打出Systrace看一下。延时加载也是一个比较好的策略,但难点就在于延时多久,这个时间并不好掌控。
1、延时加载 IdleHandler
/**
* Callback interface for discovering when a thread is going to block
* waiting for more messages.
*/
public static interface IdleHandler {
/**
* Called when the message queue has run out of messages and will now
* wait for more. Return true to keep your idle handler active, false
* to have it removed. This may be called if there are still messages
* pending in the queue, but they are all scheduled to be dispatched
* after the current time.
*/
boolean queueIdle();
}
简单来说,就是当MessageQueue中没有更多的消息的时候就会回调queueIdle()这个方法,返回true的话,当MessageQueue中没有消息的时候还会继续回调这个方法,返回false则会在执行完之后移除掉这个监听。
原理就是这么简单了,接下来就是动手优化代码了,代码也很简单。
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// ...
// 拿到主线程的MessageQueue
Looper.myQueue().addIdleHandler(new MessageQueue.IdleHandler() {
@Override
public boolean queueIdle() {
// 在这里去处理你想延时加载的东西
delayLoad();
// 最后返回false,后续不用再监听了。
return false;
}
});
}
写起来一点都不难,只是我们需要掌握这么一个知识点而已。这里多说一句,网上很多关于冷启动优化的文章都说到了ViewPager的懒加载,即等到用户滑动过去的时候才去加载界面,我们在项目中最开始也是这样做的,但其实这样的体验真的很不好,所以我们利用IdleHandler做了一个延时加载,即不影响主界面的启动工作,又能在主线程空闲下来的时候立刻去加载出其它的Tab,在性能和体验之间找到一个最好的平衡。
三、App 瘦身
App 瘦身包括代码瘦身和资源瘦身,通常的做法如下:
- Inspect Code :Android Studio 提供的代码审查工具,实际上是内嵌了 Lint
- 代码混淆
- 图片格式的选择:如果对图片的要求不高,可以换成 565
- 接入资源混淆
- 减少 Dex 数量
四、线程优化
线程优化主要是减少 CPU 调度带来的波动,让启动时间更稳定。如果启动过程中有太多的线程一起启动,会给 CPU 带来非常大的压力,尤其是比较低端的机器。过多的线程同时跑会让主线程的 Sleep 和 Runnable 状态变多, 增加了应用的启动速度,优化的过程中要注意:
控制线程数量 – 线程池
检查线程间的锁 ,防止依赖等待
使用合理的启动架构
微信内部使用的 mmkernel
阿里 Alpha
五、业务梳理
这里涉及到具体的业务,每个 App 都不一样,但是所要做的事情都是一样的,下面是邵文在高手课里面提到的:
- 梳理清楚启动过程中的每一个模块,哪些是一定需要的,那些是可以砍掉,那些是可以懒加载的
- 根据不同的业务场景决定不同的启动模式
- 懒加载防止集中化,否则容易出现首页显示后用户无法操作的情形
总的来说,用以下四个维度分整理启动的各个点
- 必要且耗时:启动初始化,考虑用线程来初始化
- 必要不耗时:首页绘制
- 非必要但耗时:数据上报、插件初始化
- 非必要不耗时:不用想,这块直接去掉,在需要用的时再加载
一句话概述,要提高应用的启动速度,核心思想是在启动过程中少做事情,越少越好。
六、业务优化
通过梳理之后,剩下的都是启动过程一定要用的模块。这个时候,我们只能硬着头皮去做进一步的优化。优化前期需要“抓大放小”,先看看主线程究竟慢在哪里。最理想是通过算法进行优化,例如一个数据解密操作需要 1 秒,通过算法优化之后变成 10 毫秒。退而求其次,我们要考虑这些任务是不是可以通过异步线程预加载实现,但需要注意的是过多的线程预加载会让我们的逻辑变得更加复杂。业务优化做到后面,会发现一些架构和历史包袱会拖累我们前进的步伐。比较常见的是一些事件会被各个业务模块监听,大量的回调导致很多工作集中执行,部分框架初始化“太厚”,例如一些插件化框架,启动过程各种反射、各种 Hook,整个耗时至少几百毫秒。还有一些历史包袱非常沉重,而且“牵一发动全身”,改动风险比较大。但是我想说,如果有合适的时机,我们依然需要勇敢去偿还这些“历史债务”。
网友评论