App体系化优化之启动优化(一启动时间分析)
提示:列表可左右滑动查看。
<p>app的启动模式分为三种:<br><br>1.冷启动<br><br>冷启动耗时最久,衡量的保准最多<br><br>Click Event - IPC - Process.start - ActivityThread - bindApplication - LifeCycle - ViewRootImpl<br><br>用户在桌面点击app 发起一个IPC操作,通过Process.start 然后创建ActivityThread,是每一个单独app进程的入口,消息循环的创建,然后通过反射创建application调用于application相关的生命周期,最后就是创建我们常用的Activity的生命周期,当Activity的生命周期完毕后,就会进入到ViewRootImpl进行真正的界面绘制。<br><br>2.热启动<br><br>最简单,最快<br><br>后台 - 前台<br><br>3.温启动<br><br>相对冷启动比较快一些<br><br>LifeCycle<br><br> <br><br>根据互联网行业的8秒原则,我们需要控制冷启动的启动速度,那么我们来看冷启动都做了一些什么呢?<br><br>冷启动:<br><br>1.启动app<br><br>2.加载空白页(图片替换)<br><br>3.创建进程<br><br>4.创建application<br><br>5.启动出线程<br><br>6.创建MainActivity<br><br>7.加载布局<br><br>8.布置屏幕<br><br>9.首帧绘制<br><br>查看启动耗时:<br><br>方法1:<br><br>命令:adb命令观察app启动的时间 (线下使用,无法带到线上)<br><br>adb shell am start -W -n 包名/类名 或者 adb shell am start -W 包名/类名<br><br>比如我自己的app:adb shell am start -W -n com.yinyan.ywf.app/com.cfs.app.ui.activity.sp.SpActivity<br><br>macdeMac-mini:~ mac$ adb shell am start -W -n com.yinyan.ywf.app/com.cfs.app.ui.activity.sp.SpActivity<br>Starting: Intent { cmp=com.yinyan.ywf.app/com.cfs.app.ui.activity.sp.SpActivity }<br>Status: ok<br>Activity: com.yinyan.ywf.app/com.cfs.app.ui.activity.sp.SpActivity<br>ThisTime: 2654 最后Activity启动耗时<br>TotalTime: 2654 所有Activity启动的耗时(包含闪屏)<br>WaitTime: 2673 AMS启动Activity的总耗时<br>Complete<br><br>方法2:手动打点(线上捕获)</p><pre><code>/**<br> * 启动时间捕获 手动打点<br> */<br>public class LaunchTimer {<br> <br> private static long sTime;<br> <br> public static void startRecord(){<br> sTime = System.currentTimeMillis();<br> }<br> <br> public static void endRecord(){<br> long cost = System.currentTimeMillis() - sTime;<br> Logger.i("cost = ",cost);<br> }<br>}</code></pre><p>启动时间记录,在Application的attachBaseContext()方法中调用 LaunchTimer.startRecord()<br><br>结束的调用建议放在自己adapter的第一个item加载出来,或者activity渲染完毕的生命周期中,不要放在首帧回调(onWindowFocusChanged)的位置,因为首帧回调未必绘制完毕了页面,是不准确的。<br><br>现在我们形成对比 我们先看看SophixApplitcation</p><pre><code>@Override<br> protected void attachBaseContext(Context base) {<br> super.attachBaseContext(base);<br> LaunchTimer.startRecord();<br>// 如果需要使用MultiDex,需要在此处调用。<br>// MultiDex.install(this);<br> initSophix();<br> }</code></pre><p style="outline: 0px; margin-top: 0px; margin-bottom: 16px; font-size: 16px; color: rgb(77, 77, 77); overflow: auto hidden; overflow-wrap: break-word; font-family: -apple-system, "SF UI Text", Arial, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", sans-serif, SimHei, SimSun; line-height: 26px !important;">接下来对比一下首帧绘制和FeedShow之后的启动时间</p><p style="outline: 0px; margin-top: 0px; margin-bottom: 16px; font-size: 16px; color: rgb(77, 77, 77); overflow: auto hidden; overflow-wrap: break-word; font-family: -apple-system, "SF UI Text", Arial, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", sans-serif, SimHei, SimSun; line-height: 26px !important;">IndexActivity</p><pre><code>@Override<br> public void onWindowFocusChanged(boolean hasFocus) {<br> super.onWindowFocusChanged(hasFocus);<br> LaunchTimer.endRecord("onWindowFocusChanged");<br> freshFragmnet();<br> }</code></pre><pre style="outline: 0px; margin-top: 0px; margin-bottom: 24px; padding: 8px; position: relative; font-family: Consolas, Inconsolata, Courier, monospace; font-size: 14px; line-height: 22px; background-color: rgb(255, 255, 255);">IndexActivity - HomeFragment - BusinessAdapter中的第一个Feed加载出来的时候</pre><p style="outline: 0px; margin-top: 0px; margin-bottom: 16px; font-size: 16px; color: rgb(77, 77, 77); overflow: auto hidden; overflow-wrap: break-word; font-family: -apple-system, "SF UI Text", Arial, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", sans-serif, SimHei, SimSun; line-height: 26px !important;">mHasRecorded自己声明一下即可 布尔类型</p><pre><code>@Override<br> public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int position) {<br> Holder holder = (Holder) viewHolder;<br> <br> /**<br> * 启动首次绘制时间统计<br> */<br> if(position == 0 && !mHasRecorded){<br> mHasRecorded = true;<br> holder.ll_business.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {<br> @Override<br> public boolean onPreDraw() {<br> holder.ll_business.getViewTreeObserver().removeOnPreDrawListener(this);<br> LaunchTimer.endRecord("FeedShow");<br> return true;<br> }<br> });<br> }<br>}</code></pre><p><img src="https://51techud.yykj.com:9002/forumpic/20210722153019_bl.png" style="max-width:100%;"><br></p>
赞(0)
收藏(0)
分享
相关标签: