抖音优化的思路

抖音原文

咱们着重看 这一部分

抖音主线程音讯调度优化 完结

尽管没有代码,可是文字描述的也够清楚了,咱们能够总结概括一下,抖音的优化思路 ,然后就能够尝试去完结它了

1.acitivity 跳转的 生命周期 音讯 是能够 进行优化的 ,说白了 便是 让这些生命周期音讯 的优先级进步 ,尽早的让他履行

  1. 要提升doFrame的音讯优先级, 这儿其实用音讯屏障 就能够完结,这个咱们后面再说, 这儿就只要知道 这个优化 能够进步首帧烘托 速度即可

  2. 自定义Printer 是要害, 这个应该做过主线程音讯卡顿监听的同学 都很了解了。

  3. 在这个自定义Printer中 遍历音讯类型 就能够完结上述的优化思路

  4. 一定得在音讯处理完毕之后 再调整音讯次序, 这个其实仔细想想就理解为啥要这么做,

能够参阅 得物的完结 ,该文章是拿Observer去完结的,有android版别的限制,尤其是一些hidden api,用起来比较麻烦,可是思路是很棒的,有兴趣的能够多看看。

我这儿便是基于Printer这个接口来完结了,没什么hidden api 需要处理。

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罢了

这个其实没啥难度

mainHandler = Reflect.onClass("android.app.ActivityThread").field("sCurrentActivityThread").field("mH").get()

有了他,咱们就能够发送各种音讯 让ActivityThread 去处理啦

一些基本处理

首先要定义一组变量 其实便是为了判别是不是跳转类型的音讯

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循环的方法 来遍历这个音讯列表中的音讯,判别类型, 这儿代码简略 就不过多讲了,

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++
    }    

进步页面跳转音讯的优先级

有了前面的基本循环今后 便是考虑怎么调整音讯优先级

  1. 找到对应的jump类型的音讯
  2. 把这个音讯放到行列头部去
  3. 由于你把音讯放到行列头部了,所以你有必要把 message的preMsg 的next指针 指向 message的下一个next即可 不然你行列中就有重复的音讯了,这儿千万不要忘记了。

其实便是一个很简略的 链表删去

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的优先级,便是要想办法 进步同步屏障音讯的优先级

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
    }
}