抖音字体大小设置方法安卓 抖音字体大小设置方法( 十 )


创建自定义的 Printer 通过 Looper 的 setMessageLogging 接口替换原有的 Printer,并对原始的 Printer 进行转发;在 Application 的 onCreate、MainActivity 的 onResume 中更新下一个待调度的消息,Application 的 onCreate 之后预期的目标消息是 Launch Activity,MainActivity 的 onResume 之后的预期消息则是渲染相关的 doFrame 消息 。为了缩小影响范围,在启动完成或者执行了非正常路径后则会对 disable 掉消息调度;消息调度的具体执行则是在自定义 Printer 的 println 方法中进行的,在 println 方法中遍历主线程消息队列,根据 message.what 和 message.getTarget()判断在消息队列中是否存在目标消息,如果存在则将其移动到头部优先执行;1.6.2 主线程耗时消息优化
通过主线程消息调度,我们可以在一定程度上解决主线程消息对启动速度的影响,但是其也存在一定的局限性:
只能调整已经在消息队列中的消息,比如在 MainActivity onResme 之后存在一个耗时的主线程消息,而此时 doFrame 的消息还没有进入主线程的消息队列,那我们则需要执行完我们的耗时消息才能执行 doFrame 消息,其仍然会对启动速度有所影响;治标不治本,虽然我们将主线程耗时消息从启动阶段移走,但是在启动后仍然会有卡顿存在 。
基于这两个原因我们需要对启动阶段主线程的耗时消息进行优化 。
一般来说主线程耗时消息大部分是业务强相关的,可以直接通过 trace 工具输出的主线程的堆栈发现问题逻辑并进行针对性的优化,这里主要介绍一个其他产品也可能会遇到的 case 的优化——WebView 初始化造成的主线程耗时 。
在我们的优化过程中发现一个主线程较大的耗时,其调用堆栈第一层为 WebViewChromiumAwInit.startChromiumLocked,是系统 Webview 中的代码,通过分析 WebView 代码发现其是在 WebViewChromiumAwInit 的 ensureChromiumStartedLocked 中 post 到主线程的,在每个进程周期首次使用 Webview 都会执行一次,无论是在主线程还是子线程调用最终都会被 post 到主线程造成耗时,因此我们无法通过修改调用线程解决主线程卡顿的问题;同时由于是系统代码我们也无法通过修改代码实现的方式去进行解决,因此我们只能从业务层从使用的角度尝试是否可以进行优化 。

抖音字体大小设置方法安卓 抖音字体大小设置方法


void ensureChromiumStartedLocked(boolean onMainThread) {
//省略其他逻辑
// We must post to the UI thread to cover the case that the user has invoked Chromium
// startup by using the (thread-safe) CookieManager rather than creating a WebView.
PostTask.postTask(UiThreadTaskTraits.DEFAULT, new Runnable() {
@Override
public void run() {
synchronized (mLock) {
startChromiumLocked();
}
}
});
while (!mStarted) {
try {
// Important: wait() releases |mLock| the UI thread can take it ??
mLock.wait();
} catch (InterruptedException e) {
}
}
}
问题定位
从业务角度优化我们首先需要找到业务的使用点,虽然我们通过分析代码定位到耗时消息是 Webview 相关的,但是我们仍然无法定位到最终的调用点 。要定位最终的调用点,我们需要对WebView 相关调用流程有所了解 。系统的 WebView 是一个独立的 App,其他应用对于 Webview 的使用都需要经过一个叫 WebViewFactory 的 framework 类,在这个类中首先会通过 Webview 的包名获取到 Webview 应用的 Context,然后通过获取到的 Context 获得 Webview 应用的 Classloader,最后通过 ClassLoader 去加载 Webview 的相关 so,反射加载 Webview 中的 WebViewFactoryProvider 的实现类并进行实例化,后续对于 WebiView 的相关调用都是通过 WebViewFactoryProvider 接口进行的 。

推荐阅读