抖音优化的思路
我们着重看 这一部分

虽然没有代码,但是文字描述的也够清楚了,我们可以总结归纳一下,抖音的优化思路 ,然后就可以尝试去实现它了
1.acitivity 跳转的 生命周期 消息 是可以 进行优化的 ,说白了 就是 让这些生命周期消息 的优先级提高 ,尽早的让他执行
-
要提升doFrame的消息优先级, 这里其实用消息屏障 就可以完成,这个我们后面再说, 这里就只要知道 这个优化 可以提高首帧渲染 速度即可
-
自定义Printer 是关键, 这个应该做过主线程消息卡顿监听的同学 都很熟悉了。
-
在这个自定义Printer中 遍历消息类型 就可以完成上述的优化思路
-
一定得在消息处理结束之后 再调整消息顺序, 这个其实仔细想想就明白为啥要这么做,
Activity 跳转消息流程
<=android8
在android的老版本中 activity的页面跳消息

主要关注下 message的what的值即可

记住这个100和101的值,后续我们会用到
>=android9
而从android9 开始 页面的跳转消息 就变成了 excute_transaction

继续跟一下,注意这个常量值


关于activity 生命周期的消息 其实就是封装在 这个activitylifecycleitem 这个类中
我们其实最关注的就是

到这里我们就搞清楚了 >=android9.0 的 页面跳转消息的 类型
joor 反射库
由于这次需要反复利用反射来做许多事情,为了简单 我们使用joor反射库 来做,具体就不介绍用法了,自行google
获取activityThread中的 handler
既然要调整消息的顺序,我们自然要用到handler,而且必须是activityThread中的 handler,去源码中找一下



找到以后 无非就是反射 拿到这个handler而已
这个其实没啥难度
kotlin
mainHandler = Reflect.onClass("android.app.ActivityThread").field("sCurrentActivityThread").field("mH").get()
有了他,我们就可以发送各种消息 让ActivityThread 去处理啦
一些基本处理
首先要定义一组变量 其实就是为了判断是不是跳转类型的消息
kotlin
class FakeActivityLifecycleItem {
companion object {
// public static final int EXECUTE_TRANSACTION = 159;
const val EXECUTE_TRANSACTION = 159
const val ON_PAUSE = 4
const val ON_RESUME = 3
const val LAUNCH_ACTIVITY = 100
const val PAUSE_ACTIVITY = 101
}
}
然后 我们就要从looper中 取得这个queue,然后取到message,用while循环的方式 来遍历这个消息列表中的消息,判断类型, 这里代码简单 就不过多讲了,
kotlin
if (log?.contains("Finished to Handler") == true) {
// 获取主线程的queue
val mainMsg = Looper.getMainLooper().queue
// 获取第一个消息
var message: Message? = Reflect.on(mainMsg).field("mMessages").get()
// 获取前一个消息
var preMessage: Message? = null
// 记录该消息 在原来链表中的第几个位置
var index = 0
// 遍历消息链表
while (message != null) {
// 因为消息中心 是一个链表,所以 要调整顺序 必然涉及到 preMessage的指针 改变
if (preMessage != null) {
}
preMessage = message
message = (Reflect.on(message).field("next").get())
index++
}
提高页面跳转消息的优先级
有了前面的基本循环以后 就是考虑如何调整消息优先级
- 找到对应的jump类型的消息
- 把这个消息放到队列头部去
- 因为你把消息放到队列头部了,所以你必须把 message的preMsg 的next指针 指向 message的下一个next即可 否则你队列中就有重复的消息了,这里千万不要忘记了。
其实就是一个很简单的 链表删除
kotlin
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) {
// android8 以下
if (message.what == FakeActivityLifecycleItem.LAUNCH_ACTIVITY ||
message.what == FakeActivityLifecycleItem.PAUSE_ACTIVITY
) {
val copyJumpMsgAndroid8 = Message.obtain(message)
// 这里一定要设置异步消息
if (message.isAsynchronous) {
copyJumpMsgAndroid8.isAsynchronous = true
}
val nextMessage = Reflect.on(message).field("next").get<Message>()
Reflect.on(preMessage).set("next", nextMessage)
// 将关键的消息放到队列头部去执行
mainHandler?.sendMessageAtFrontOfQueue(copyJumpMsgAndroid8)
break
}
} else {
// android9 及 以上
if (message.what == FakeActivityLifecycleItem.EXECUTE_TRANSACTION) {
val sr = Reflect.on(message.obj).field("mLifecycleStateRequest").call("getTargetState").get<Int>()
if (sr == FakeActivityLifecycleItem.ON_PAUSE || sr == FakeActivityLifecycleItem.ON_RESUME) {
val copyJumpMsgAndroid9 = Message.obtain(message)
if (message.isAsynchronous) {
copyJumpMsgAndroid9.isAsynchronous = true
}
Log.e("lixiao", "preMessage!=null result:$sr index:$index")
val nextMessage = Reflect.on(message).field("next").get<Message>()
Reflect.on(preMessage).set("next", nextMessage)
// 将关键的消息放到队列头部去执行
mainHandler?.sendMessageAtFrontOfQueue(copyJumpMsgAndroid9)
break
}
}
}
提高首帧表现
可以重点参考同步屏障
这篇文章的说明
讲白了,你要提高doFrame的优先级,就是要想办法 提高同步屏障消息的优先级
kotlin
if (message.target == null) {
val copy = Message.obtain(message)
val success = mainHandler?.sendMessageAtFrontOfQueue(copy)
// 这里千万不要遗忘
copy.target = null
if (success == true) {
val next = Reflect.on(message).field("next").get<Message>()
Reflect.on(preMessage).set("next", next)
Reflect.on(message).set("next", null)
break
} else {
break
}
}