精华内容
下载资源
问答
  • 启动速度优化

    2020-02-06 22:52:54
    一个启动速度慢的APP 不符合用户期望,可能会令用户失望,并且可能会导致用户对您的应用程序评价不佳,甚至会卸载你的应用。 本文将讨论如何优化应用的启动时间,首先我们需要了解APP启动的相关内容。 1.分析...

    用户希望APP能够快速响应并加载。 一个启动速度慢的APP 不符合用户期望,可能会令用户失望,并且可能会导致用户对您的应用程序评价不佳,甚至会卸载你的应用。

    本文将讨论如何优化应用的启动时间,首先我们需要了解APP启动的相关内容。

     

    1.分析工具: 要想提升App的启动速度, 我们需要先找到拖后腿的点, 要想找到这些点, 我们就需要借助我们的工具了。我们使用Traceview来分析我们的启动过程。

    1.1 Traceview介绍

    Traceview是一个性能分析工具, 主要是分析当前线程情况, 各个方法执行时间等。如下:

    指标说明:

    Incl(Inclusive) Cpu Time:方法本身和其调用的所有子方法占用CPU时间.

    Excl(Exclusive) Cpu Time:方法本身占用CPU时间。

    Incl Real Time:方法(包含子方法)开始到结束用时。

    Excl Real Time:方法本身开始到结束用时。

    Call + Recursion Calls/Total:方法被调用次数 + 方法被递归调用次数。

    Cpu Time/Call:方法调用一次占用CPU时间。

    Real Time/Call:方法调用一次实际执行时间。

    一般来说, 我们使用Real Time/Call排序来找出耗时多的方法

    有必要解释下CPU Time和Real Time:

    • CPU Time 方法实际执行时间(不包括io等待时间)
    • Real Time 方法开始结束时间差(包括等待时间)

     

    1.2 Traceview使用

    有两种方式来使用Traceview:

    a, 通过DDMS:

    点击开始时会弹出一个选择trace模式的框, 默认选中”Sample based profiling”即可:

    Sample based profiling(基于样本分析)

    根据采样时间间隔来规律的打断VM来记录方法调用栈(Call Stack), 开销和采样频率成比例。

    Trace based profiling(基于完整trace数据分析)

    记录每个方法的出入口, 每个方法执行时都开启记录, 无论多小的方法, 因此开销很大。

    b, 使用代码:

    1. // 在自己想要开始调试的地方start 
    2. Debug.startMethodTracing("GithubApp"); 
    3. // 在合适的地方stop 
    4. Debug.stopMethodTracing(); 

    注: 以上方法开启trace的方式相当于”Trace based profiling”, 会记录每个方法的执行. Android 4.4及以上可以调用startMethodTracingSampling()来用代码开启”Sample based profiling”的trace方式。

     

    2, App启动流程分析

     

    • 要想优化App启动流程, 必先了解其启动过程。
    • 具体过程请参看这篇译文: Android Application启动流程分析。
       

    3, App启动方式

     

    通常来说, 一个App启动也会分如下三中不同的状态:

    冷启动

    • App没有启动过或App进程被killed, 系统中不存在该App进程, 此时启动App即为冷启动。
    • 冷启动的流程即为第2节所描述的App启动流程的全过程, 需要创建App进程, 加载相关资源, 启动Main Thread, 初始化首屏Activity等。
    • 在这个过程中, 屏幕会显示一个空白的窗口(颜色基于主题), 直至首屏Activity完全启动。

    应用发生冷启动时,系统有三件任务要做:

        加载启动App;
        App启动之后立即展示出一个空白的Window;
        创建App的进程;

    创建App进程后,会马上执行以下任务:

        初始化应用中的对象 (比如 Application 中的工作);
        启动主线程 (UI 线程) ;
        创建第一个 Activity;
        加载内容视图 (Inflating) ;
        计算视图在屏幕上的位置排版 (Laying out);
        进行第一次绘制 (draw)。
    只有当应用完成第一次绘制,系统当前展示的空白背景才会消失,才会被 Activity 的内容视图替换掉。也就是这个时候,用户才能和我们的应用开始交互。

    启动流程大致如下:

    点击Launcher 上的 icon开加载app -->立即显示白屏或黑屏等 --> Application onCreate --> Activity Init----> Activity onCreate ---> 初始化数据,填充显示View ---> Activity onResume等,下图展示了冷启动的时间线:

     

     

    热启动

    • 热启动意味着你的App进程只是处于后台, 系统只是将其从后台带到前台, 展示给用户。
    • 类同与冷启动, 在这个过程中, 屏幕会显示一个空白的窗口(颜色基于主题), 直至activity渲染完毕。

    APP的热启动要比 冷启动简单得多,内存开销也更低。APP热启动时候,所有的系统都是把你的Activity带到前台。如果APP的所有Activity仍驻留在内存中,则APP可以避免重复对象初始化、布局绘制和显示等工作。
    如果APP 在内存中被清理掉,比如调用ontrimmemory(),当响应热启动时,这些对象将重新被创建。

    热启动与冷启动相同的屏幕行为:
    系统进程会显示一个空白屏幕,直到应用程序完成渲染后将此空白屏幕移除掉,此屏幕创建会在加载APP时候立即创建,如需查看创建流程,需要查看PhoneWindosMangerAddWindows方法。


     

    温启动

    介于冷启动和热启动之间, 一般来说在以下两种情况下发生:

    • 用户back退出了App, 然后又启动. App进程可能还在运行, 但是activity需要重建。
    • 用户退出App后, 系统可能由于内存原因将App杀死, 进程和activity都需要重启, 但是可以在onCreate中将被动杀死锁保存的状态(saved instance state)恢复。

    通过三种启动状态的相关描述, 可以看出我们要做的启动优化其实就是针对冷启动. 热启动和温启动都相对较快。

     

    4, 哪些地方是App快速启动的敌人

     

    这里我们重点讨论用户点击桌面后的APP启动,通过startActivity方式的启动。

    调用startActivity,该方法经过层层调用,最终会调用ActivityStackSupervisor.java中的startSpecificActivityLocked,当activity所属进程还没启动的情况下,则需要创建相应的进程.

    进程启动后系统还有一个工作就是:进程启动后立即显示应用程序的空白启动窗口。

    一旦系统创建应用程序进程,应用程序进程就会负责下一阶段。这些阶段是:
    1.创建应用程序对象
    2.启动主线程
    3.创建主要Activity
    4.绘制视图(View)
    5.布局屏幕
    6.执行初始化绘制

    而一旦App进程完成了第一次绘制,系统进程就会用Main Activity替换已经展示的Background Window,此时用户就可以使用App了。

     

    根据冷启动的时间图, 可以看出, 对于App来说, 我们可以控制的启动时间线的点无外乎:

    • Application的onCreate
    • 首屏Activity的渲染

    而我们现在的App动不动集成了很多第三方服务, 启动时需要检查广告, 注册状态等等一系列接口都是在Application的onCreate或是首屏的onCreate中做的。

    • 很多第三方平台的SDK文档也都是这么建议的。

     

    这里很明显有两个优化点:


    Application OnCrate()优化


    当APP启动时,空白的启动窗口将保留在屏幕上,直到系统首次完成绘制应用程序。此时,系统进程会交换应用程序的启动窗口,允许用户开始与应用程序进行交互。如果应用程序中重载了Application.onCreate(),系统会调用onCreate()方法。之后,应用程序会生成主线程(也称为UI线程),并通过创建MainActivity来执行任务。


    Activity onCreate()优化
    onCreate()方法对加载时间的影响最大,因为它以最高的开销执行工作:加载并绘制视图,以及初始化Activity运行所需的对象。

     

    Google也给出了启动加速的方向:

    1、利用提前展示出来的Window,快速展示出来一个界面,给用户快速反馈的体验;
    2、 避免在启动时做密集沉重的初始化(Heavy app initialization);
    3、 定位问题:避免I/O操作、反序列化、网络操作、布局嵌套等

    Application OnCrate()优化

    在Application初始化的地方做太多繁重的事情是可能导致严重启动性能问题的元凶之一。Application里面的初始化操作不结束,其他任意的程序操作都无法进行。Application的onCreate中会做大量第三方组件的初始化工作,其实很多组件是需要做区别对待的,有些可以做延迟加载,有些可以放到其他的地方做初始化操作,特别需要留意包含Disk IO操作,网络访问等严重耗时的任务,他们会严重阻塞程序的启动。

    注意点:

        项目是多进程架构,只在主进程执行Application的onCreate();
        流程梳理,延后执行;
        异步加载、延时加载、懒加载
     

    1.第三方SDK初始化的处理


    Application是程序的主入口,很多三方SDK示例程序中都要求自己在Application OnCreate时做初始化操作。这就是增加Application OnCreate时间的主要元凶,所以需要尽量避免在Application onCreate时同步做初始化操作。比较好的解决方案就是对三方SDK就行懒加载,不在Application OnCreate()时初始化,在真正用到的时候再去加载。

    Application OnCreate 避免在主线程做大量耗时操作,例如和IO相关的逻辑,这样都会影响到应用启动速度。如果必须要做需要放到子线程中。
     

    Activity onCreate()优化

    避免首个Activity的onCreate进行太多的工作

    使用延迟加载。确保在Activity的页面显示出来之后再进行加载数据,避免过早或过晚的加载导致页面空白时间过长。

    减少LaunchActivity的View层级,减少View测量绘制时间。
    避免主线程做耗时操作

     

    用户体验优化

    消除启动时的白屏/黑屏

     

    为什么启动时会出现短暂黑屏或白屏的现象?当用户点击你的app那一刻到系统调用Activity.onCreate()之间的这个时间段内,WindowManager会先加载app主题样式中的windowBackground做为app的预览元素,然后再真正去加载activity的layout布局。
    很显然,如果你的application或activity启动的过程太慢,导致系统的BackgroundWindow没有及时被替换,就会出现启动时白屏或黑屏的情况(取决于你的主题是Dark还是Light)。

    使用透明主题 <item name="android:windowIsTranslucent">true</item>   Activity.onCreate()之前App不做显示

     

    如何对启动时间进行量化?

     

    1.目前为止见过最最牛逼的是使用机械手和高速相机测试,手机开机后使用机械手点击应用桌面图标,高速相机记录启动过程,后续通过程序分析视频,从机械手点击图标到Activity显示出来使用了多少时间。这种方式是最直观和精确的,但是成本也很高。

     

    2.通过shell 命令

    adb shell am start -W [packageName]/[packageName.MainActivity]


    adb [-d|-e|-s <serialNumber>] shell am start -S -W [packageName]/[packageName.MainActivity] -c android.intent.category.LAUNCHER -a android.intent.action.MAIN

     

    执行成功后将返回三个测量到的时间:


    ThisTime:         一般和TotalTime时间一样,除非在应用启动时开了一个透明的Activity预先处理一些事再显示出主Activity,这样将比TotalTime小。
    TotalTime:       应用的启动时间,包括创建进程+Application初始化+Activity初始化到界面显示。
    WaitTime:       一般比TotalTime大点,包括系统影响的耗时。

    开发者一般只要关心 TotalTime 即可,这个时间才是自己应用真正启动的耗时。

    3.Traceview

    告诉我们每一个方法执行了多长时间.这个工具可以通过 Android Device Monitor 或者从代码中启动。


    3.1 Android Device Monitor启动

    启动应用,点击 Start Method Tracing,应用启动后再次点击,会自动打开刚才操作所记录下的.trace文件,建议使用DDMS来查看,功能更加方便全面。

    3.2 代码启动

    ①在onCreate开始和结尾打上trace

         Debug.startMethodTracing("GithubApp");
    	...
         Debug.stopMethodTracing();

    运行程序, 会在sdcard上生成一个"GithubApp.trace"的文件.

    ②通过adb pull将文件导出到本地

    ③打开DDMS分析trace文件

    ④分析trace文件

     

    4.Systrace:

    在onCreate方法里面添加trace.beginSection()与trace.endSection()方法来声明需要跟踪的起止位置,系统会帮忙统计中间经历过的函数调用耗时,并输出报表。

     

    5:响应时间+白屏 测试- Timeline方法

     

    小米视频国际版优化前后日志对比:

     

    优化之前:

    02-10 19:11:56.775  1850  2311 I Timeline: Timeline: App_transition_stopped time:99622803

    02-10 19:11:59.308  2688  2688 I Timeline: Timeline: Activity_launch_request time:99625336 intent:Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.miui.videoplayer/com.miui.video.global.app.LauncherActivity bnds=[839,490][1017,668] (has extras) }

    02-10 19:11:59.433  1850  2928 I Timeline: Timeline: App_transition_ready time:99625461

    02-10 19:12:00.584  1850  3477 I Timeline: Timeline: App_transition_ready time:99626612

    02-10 19:12:00.592  1850  3477 I Timeline: Timeline: App_transition_ready time:99626620

    02-10 19:12:00.669 25989 25989 I Timeline: Timeline: Activity_launch_request time:99626697 intent:Intent { cmp=com.miui.videoplayer/com.miui.video.global.activity.HomeActivity (has extras) }

    02-10 19:12:00.775  1850  3601 I Timeline: Timeline: App_transition_ready time:99626803

    02-10 19:12:00.793  1850  2311 I Timeline: Timeline: App_transition_ready time:99626821

    02-10 19:12:01.515  1850  2311 I Timeline: Timeline: App_transition_ready time:99627543

    02-10 19:12:01.902  1850  3601 I Timeline: Timeline: App_transition_ready time:99627930

    02-10 19:12:01.913  1850  3601 I Timeline: Timeline: App_transition_ready time:99627941

    02-10 19:12:02.021  1850  3484 I Timeline: Timeline: App_transition_ready time:99628049

    02-10 19:12:02.078  1850  2311 I Timeline: Timeline: App_transition_ready time:99628106

    02-10 19:12:02.409  1850  2050 I Timeline: Timeline: Activity_windows_visible id: ActivityRecord{5704311 u0 com.miui.videoplayer/com.miui.video.global.activity.HomeActivity t4304} time:99628437

    02-10 19:12:02.411  1850  2311 I Timeline: Timeline: App_transition_stopped time:99628439

     

    优化之后:

    02-10 17:37:37.114  2688  2688 I Timeline: Timeline: Activity_launch_request time:94136890 intent:Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.miui.videoplayer/com.miui.video.global.activity.HomeActivity bnds=[839,490][1017,668] (has extras) }

    02-10 17:37:37.243  1850 14096 I Timeline: Timeline: App_transition_ready time:94137019

    02-10 17:37:38.680  1850  1904 I Timeline: Timeline: App_transition_ready time:94138457

    02-10 17:37:38.687  1850  1904 I Timeline: Timeline: App_transition_ready time:94138463

    02-10 17:37:38.828  1850  3499 I Timeline: Timeline: App_transition_ready time:94138605

    02-10 17:37:38.863  1850  2311 I Timeline: Timeline: App_transition_ready time:94138639

    02-10 17:37:39.177  1850  2050 I Timeline: Timeline: Activity_windows_visible id: ActivityRecord{29919cb u0 com.miui.videoplayer/com.miui.video.global.activity.HomeActivity t4279} time:94138954

    02-10 17:37:39.179  1850  2311 I Timeline: Timeline: App_transition_stopped time:94138955


    6:可以通过在代码中增加log来计算启动时间

    优化之前:

    2020-02-10 21:41:59.688 25989-25989/com.miui.videoplayer D/TimeStatic: initialize begin

    2020-02-10 21:41:59.688 25989-25989/com.miui.videoplayer D/TimeStatic: initBase  begin

    2020-02-10 21:41:59.786 25989-25989/com.miui.videoplayer D/TimeStatic: initBase  over

    2020-02-10 21:41:59.786 25989-25989/com.miui.videoplayer D/TimeStatic: GlobalApplication initBase cost time ==  98

    2020-02-10 21:41:59.789 25989-25989/com.miui.videoplayer D/TimeStatic: initModule  begin

    2020-02-10 21:41:59.949 25989-25989/com.miui.videoplayer D/TimeStatic: initModule  over

    2020-02-10 21:41:59.949 25989-25989/com.miui.videoplayer D/TimeStatic: GlobalApplication initModule cost time ==  160

    2020-02-10 21:41:59.949 25989-25989/com.miui.videoplayer D/TimeStatic: asyncInitModule  begin

    2020-02-10 21:42:00.038 25989-25989/com.miui.videoplayer D/TimeStatic: asyncInitModule  over

    2020-02-10 21:42:00.039 25989-25989/com.miui.videoplayer D/TimeStatic: GlobalApplication asyncInitModule cost time ==  90

    2020-02-10 21:42:00.039 25989-25989/com.miui.videoplayer D/TimeStatic: initialize over

    2020-02-10 21:42:00.039 25989-25989/com.miui.videoplayer D/TimeStatic: GlobalApplication initialize cost time ==  351

    2020-02-10 21:42:00.039 25989-25989/com.miui.videoplayer D/TimeStatic: GlobalApplication onCreate cost time ==  354

    2020-02-10 21:42:00.073 25989-25989/com.miui.videoplayer D/TimeStatic: LauncherActivity onCreate  begin

    2020-02-10 21:42:00.184 25989-25989/com.miui.videoplayer D/TimeStatic: LauncherActivity onCreate  over

    2020-02-10 21:42:00.184 25989-25989/com.miui.videoplayer D/TimeStatic: LauncherActivity onCreate cost time ==  111

    2020-02-10 21:42:00.184 25989-25989/com.miui.videoplayer D/TimeStatic: LauncherActivity App cost total time ==  499

    2020-02-10 21:42:00.661 25989-25989/com.miui.videoplayer D/TimeStatic: LauncherActivity: default

    2020-02-10 21:42:00.973 25989-25989/com.miui.videoplayer D/TimeStatic: HomeActivity preAddMomentFragment  begin

    2020-02-10 21:42:00.979 25989-25989/com.miui.videoplayer D/TimeStatic: HomeActivity preAddMomentFragment  over

    2020-02-10 21:42:00.979 25989-25989/com.miui.videoplayer D/TimeStatic: HomeActivity preAddMomentFragment cost time ==  6

    2020-02-10 21:42:01.086 25989-25989/com.miui.videoplayer D/TimeStatic: HomeActivity onCreate  over

    2020-02-10 21:42:01.086 25989-25989/com.miui.videoplayer D/TimeStatic: HomeActivity onCreate cost time ==  279

    2020-02-10 21:42:01.086 25989-25989/com.miui.videoplayer D/TimeStatic: HomeActivity onCreate App cost total  time ==  1401

    2020-02-10 21:42:01.478 25989-25989/com.miui.videoplayer D/TimeStatic: HomeActivity onResume  over

    2020-02-10 21:42:01.478 25989-25989/com.miui.videoplayer D/TimeStatic: HomeActivity onResume cost time ==  12

    2020-02-10 21:42:01.478 25989-25989/com.miui.videoplayer D/TimeStatic: HomeActivity onResume App cost total  time ==  1793

     

     

    优化之后:

    2020-02-10 20:07:37.465 30530-30530/com.miui.videoplayer D/TimeStatic: initialize begin

    2020-02-10 20:07:37.465 30530-30530/com.miui.videoplayer D/TimeStatic: initBase  begin

    2020-02-10 20:07:37.565 30530-30530/com.miui.videoplayer D/TimeStatic: initBase  over

    2020-02-10 20:07:37.565 30530-30530/com.miui.videoplayer D/TimeStatic: GlobalApplication initBase cost time ==  100

    2020-02-10 20:07:37.571 30530-30530/com.miui.videoplayer D/TimeStatic: initialize over

    2020-02-10 20:07:37.571 30530-30567/com.miui.videoplayer D/TimeStatic: initModule  begin

    2020-02-10 20:07:37.571 30530-30530/com.miui.videoplayer D/TimeStatic: GlobalApplication initialize cost time ==  106

    2020-02-10 20:07:37.571 30530-30530/com.miui.videoplayer D/TimeStatic: GlobalApplication onCreate cost time ==  109

    2020-02-10 20:07:37.609 30530-30530/com.miui.videoplayer D/TimeStatic: LauncherActivity: homeActivity

    2020-02-10 20:07:37.957 30530-30530/com.miui.videoplayer D/TimeStatic: HomeActivity onCreate  over

    2020-02-10 20:07:37.957 30530-30530/com.miui.videoplayer D/TimeStatic: HomeActivity onCreate cost time ==  354

    2020-02-10 20:07:37.957 30530-30530/com.miui.videoplayer D/TimeStatic: HomeActivity onCreate App cost total  time ==  495

    2020-02-10 20:07:37.970 30530-30530/com.miui.videoplayer D/TimeStatic: HomeActivity onResume  over

    2020-02-10 20:07:37.970 30530-30530/com.miui.videoplayer D/TimeStatic: HomeActivity onResume cost time ==  5

    2020-02-10 20:07:37.970 30530-30530/com.miui.videoplayer D/TimeStatic: HomeActivity onResume App cost total  time ==  508

    2020-02-10 20:07:38.265 30530-30567/com.miui.videoplayer D/TimeStatic: initModule  over

    2020-02-10 20:07:38.266 30530-30567/com.miui.videoplayer D/TimeStatic: GlobalApplication initModule cost time ==  694

    2020-02-10 20:07:38.892 30530-30530/com.miui.videoplayer D/TimeStatic: GlobalApplication asyncInitModule cost time ==  31

    2020-02-10 20:07:39.974 30530-30530/com.miui.videoplayer D/TimeStatic: HomeActivity preAddMomentFragment  begin

    2020-02-10 20:07:39.976 30530-30530/com.miui.videoplayer D/TimeStatic: HomeActivity preAddMomentFragment  over

    2020-02-10 20:07:39.976 30530-30530/com.miui.videoplayer D/TimeStatic: HomeActivity preAddMomentFragment cost time ==  2

     

     

     

     

    展开全文
  • 主要介绍了Android应用启动速度优化的相关资料,需要的朋友可以参考下
  • 随着手机硬件的发展,手机硬件配置越来越...这里是自己在开发过程中的一些经验积累,记录下来方便自己日常查阅,本篇是启动速度优化第一篇,主要记录APP启动速度的测量方法。 一、adb命令查看启动时间 Android本身提供

    随着手机硬件的发展,手机硬件配置越来越高,计算速度,硬件性能越来越好,导致在开发过程中很容易让开发者不太去关注启动速度和性能问题。但是在发布到市场上后就会有用户反馈说启动速度慢,体验不好的问题。实际上性能问题、启动速度问题在高端机上依然存在,例如在手机内存吃紧的时候,再去启动一个APP的话还是会遇到这类问题,在低端机上就更不用说了。
    这里是自己在开发过程中的一些经验积累,记录下来方便自己日常查阅,本篇是启动速度优化第一篇,主要记录APP启动速度的测量方法。

    一、adb命令查看启动时间

    Android本身提供有可以查看APP启动速度的命令,日常开发和调试中可以使用它们快速的查看信息,方便日常的开发。但是有一个缺点是adb命令查看的时间无法反应出启动过程中每个环节的时间消耗

    1.1 adb shell am start -W

    我们可以使用这个命令来启动目标Activity,启动后终端会显示对应的启动信息

    adb shell am start -W packageName/ComponentName
    
    demo
    adb shell am start -W com.snail.memo/com.snail.memo.NoteStartActivity
    Starting: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=com.snail.memo/.NoteStartActivity }
    Status: ok
    Activity: com.snail.memo/.NoteStartActivity
    ThisTime: 332
    TotalTime: 332
    WaitTime: 359
    Complete
    
    

    可以看到,在终端输入的这段信息,各信息详细意思

    Status

    启动状态,有两种取值,ok和timeout,正常启动为ok,启动超时或者异常为timeout

    Activty

    启动的目标Activity名

    ThisTime

    表示一连串启动 Activity 的最后一个 Activity 的启动耗时。 注:Android Q之后不再有该属性

    TotalTime

    所有Activity启动耗时,包括进程创建,Application初始化,Activity实例化并初始化,到界面显示整个过程的时间

    WaitTime

    执行本条命令开始到Activity启动完成的总时间,包括整个启动过程的所有时间(AMS内部的逻辑时间和Activity真正启动的时间),统计的方法实际上是在执行命令前后分别记录了startTime和endTime,执行完成后取两者的差值

    adb shell am这条命令执行后在java层的调用代码如下:
    代码路径:

    frameworks/base/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
    

    执行代码:

    @Override
        public int onCommand(String cmd) {
            if (cmd == null) {
                return handleDefaultCommands(cmd);
            }
            final PrintWriter pw = getOutPrintWriter();
            try {
                switch (cmd) {
                    case "start":
                    case "start-activity":
                        return runStartActivity(pw);
    ........//其他命令代码
              }
          }
    }
    

    runStartActivity方法的开头会调用makeIntent方法,改方法会解析我们传递进来的option -W,匹配上-W后,把mWaitOption设置为true。然后在后面真正启动Activity的时候利用mWaitOption来处理不同的启动方式。
    makeIntent方法中的关键代码:

      return Intent.parseCommandArgs(this, new Intent.CommandOptionHandler() {
                @Override
                public boolean handleOption(String opt, ShellCommand cmd) {
                    if (opt.equals("-D")) {
                        mStartFlags |= ActivityManager.START_FLAG_DEBUG;
                    } else if (opt.equals("-N")) {
                        mStartFlags |= ActivityManager.START_FLAG_NATIVE_DEBUGGING;
                    } else if (opt.equals("-W")) {
                        mWaitOption = true;
    

    执行完以上逻辑后就会进入runStartActivity真正启动Activity的过程
    runStartActivity启动Activity代码片段,利用mWaitOption判断是调用AMS的哪个方法启动Activity,-W被指定时mWaitOption为true,因此就会调用startActivityAndWait方法进行启动Activity的操作

    if (mWaitOption) {
                    result = mInternal.startActivityAndWait(null, null, intent, mimeType,
                            null, null, 0, mStartFlags, profilerInfo,
                            options != null ? options.toBundle() : null, mUserId);
                    res = result.result;
                } else {
                    res = mInternal.startActivityAsUser(null, null, intent, mimeType,
                            null, null, 0, mStartFlags, profilerInfo,
                            options != null ? options.toBundle() : null, mUserId);
                }
    

    后面的事情就是启动Activity的流程,不在这里进行深入。
    看到这里发现一个问题,只是单独指定-W的时候,如果要测试APP的冷启动时间,每次都要手动把进程停止掉,很麻烦。如果系统可以有更加便捷的方法提供给我们就完美了。果不其然,真的有提供这个操作,那就是-S 操作

    adb shell am start -S -W packageName/ComponentName
    
    

    如此一来没执行一次命令之前系统会先forceStop掉目标进程,就可以很方便的调试冷启动时间了
    原因在于makeIntent方法中解析option的时候,如果有设置了-S,会把mStopOption设置为true。runStartActivity方法执行启动Activity之前会判断这个属性是否为true,为true的话就先调用forceStop方法停止掉目标进程

    if (mStopOption) {
                    String packageName;
                    if (intent.getComponent() != null) {
                        packageName = intent.getComponent().getPackageName();
                    } else {
                        // queryIntentActivities does not convert user id, so we convert it here first
                        int userIdForQuery = mInternal.mUserController.handleIncomingUser(
                                Binder.getCallingPid(), Binder.getCallingUid(), mUserId, false,
                                ALLOW_NON_FULL, "ActivityManagerShellCommand", null);
                        List<ResolveInfo> activities = mPm.queryIntentActivities(intent, mimeType, 0,
                                userIdForQuery).getList();
                        if (activities == null || activities.size() <= 0) {
                            getErrPrintWriter().println("Error: Intent does not match any activities: "
                                    + intent);
                            return 1;
                        } else if (activities.size() > 1) {
                            getErrPrintWriter().println(
                                    "Error: Intent matches multiple activities; can't stop: "
                                    + intent);
                            return 1;
                        }
                        packageName = activities.get(0).activityInfo.packageName;
                    }
                    pw.println("Stopping: " + packageName);
                    pw.flush();
                    mInterface.forceStopPackage(packageName, mUserId);
                    try {
                        Thread.sleep(250);
                    } catch (InterruptedException e) {
                    }
                }
    

    1.2 adb logcat

    Activity启动的时候AMS会打印出对应的log信息,我们可以过滤出需要的信息来知道启动的时间

    adb logcat -s ActivityManager:I | grep Displayed
    

    或者在AndroidStudio中自己过滤Displayed信息出来

    ActivityManager: Displayed com.snail.memo/.NoteStartActivity: +119ms
    

    二、代码打点统计启动耗时

    打点统计启动时间的方式比较简单,主要还是要先只掉Activity和APP的启动流程,然后在对应的方法中加入打点代码片段即可。
    我们知道冷启动过程中APP端最先被调用到的方法是Application的attachBaseContext方法,然后才会到onCreate,后面才会到Activity相关的周期函数。因此在统计的时候我们可以从这里入手。但是代码打点需要注意的是,启动时间优化我们是要关注的不知冷冰冰的统计数据,而是用户从点击桌面图标到真正看到APP界面的时间。因此打点的结束时间应该是视图界面绘制完成的时间。而不是Activity onCreate方法结束的时间或者onResume被调用到的时间

    2.1 直接插入代码统计

    伪代码片段

    public class TimeTrace{
        public static long sStart;
        public static long sEnd;
    
       public static void startTracing(){
          sStart = System.currentTimeMillis() 
      }
      public static void endTracing(){
        Log.d("StartTime","TotalTime:"+(System.currentTimeMillis() - sStart));
       }
    
    }
    

    在Application的attachBaseContext记录开始时间

    	@Override
    	protected void attachBaseContext(Context base) {
    		super.attachBaseContext(base);
                    TimeTrace.startTracing();
    	}
    

    在MainActivity的onCreate方法中找到一个对用于视觉感官比较强的View,在这个View进行绘制的时候进结束时间的打点和输出

    findViewById(R.id.logo).getViewTreeObserver().addOnDrawListener(new ViewTreeObserver.OnDrawListener() {
    			@Override
    			public void onDraw() {
    				if( !hasCounted ){
    					hasCounted = true;
                        TimeTrace.startTracing();
    				}
    
    			}
    		});
    

    2.2 AOP

    2.1节中的方式并没有什么问题,只是需要修改原来的业务逻辑代码,不利于维护。网上有很多文章有介绍到使用AOP的形式进行统计。自己demo之后发现确实可行。这里不再重复。
    提供一个快速集成AOP的插件,可以直接使用,非常方便:
    https://github.com/alexluotututu/aop_plugin

    三、Systrace

    实际上可以对Android 性能进行检测的有很多工具,例如Profiler,TraceView等,但是这些工具因为统计的信息比较多,个人觉得无法真正对优化的方向进行指导,比如TraceView本身在统计信息的时候自己就会滑掉一部分时间。
    因此我会直接使用Systrace来查看启动时间Systrace记录APP启动时间

    如上图所示,冷启动时间我们从bindApplicaiton开始,到第二帧绘制结束即可。
    启动分析过程中需要对每个方法进行耗时统计的话可以自己在目标方法中加入trace统计方法即可,例如我要统计initData这个方法的耗时,可以这样做

    	private void initData(){
    		TraceCompat.beginSection("InitData");
    		//do something
    		TraceCompat.endSection();
    	}
    

    使用以下命令生成trace文件,利用Chrome浏览器打开,就可以查看详细信息了

    python systrace.py -t 10 sched gfx view wm am app webview -a "com.snail.memo" -o ~/Documents/systrace_file/start_time.html 
    

    -t: 表示统计的时长
    -a: 指定目标包名
    -o: 指定输出文件

    四、高速相机

    高速相机主要是模拟人眼的场景,记录从用户点击桌面图标到看到真正画面的时间。测试工程师一般会用这个时间类评估APP冷启动时间。但是因为个人比较穷,没有用过,在此不做过多叙述

    展开全文
  • 本篇文章给大家通过实战总结了Android开发APP启动速度优化的方法以及需要注意的地方,有需要的朋友可以参考下。
  • vue 项目启动速度优化

    2021-04-21 10:24:27
  • 本文介绍了Firefox浏览器的启动速度优化方法。
  • Android内核开发:系统启动速度优化-Android OS启动优化(转) Android系统的启动优化主要分为三大部分:   (1) Bootloader优化 (2) Linux Kernel的剪裁与优化 (3) Android OS部分的剪裁与优化   ...

    Android内核开发:系统启动速度优化-Android OS启动优化(转)

    Android系统的启动优化主要分为三大部分:

     

    (1) Bootloader优化

    (2) Linux Kernel的剪裁与优化

    (3) Android OS部分的剪裁与优化

     

    本文重点关注Android OS部分的启动优化,值得关注的优化点分别介绍如下:

     

    1. 精简preload的classes和resource

     

    前面介绍过,由于所有的Android应用程序都是从Zygote进程fork出来的,所以为了共享一些class和resourse资源,Zygote进程初始化过程中,会预先加载一些常用的java class和资源文件到进程的内存中,这样其他应用fork出来后就不用再次加载了,从而提高了应用的启动速度。

     

    这个过程是可以精简和优化的,你可以减少一些classes和resource的加载,从而加快系统的启动速度。本过程涉及到的文件:

     

    frameworks/base/preload-classes

     

    frameworks/base/core/res/res/values/arrays.xml

     

    2.  精简native service和java service

     

    前面介绍过,Android OS的启动本质上就是启动一系列的本地服务和Java服务,Android系统的所有功能都是通过这些服务间接提供的。

     

    这些服务有很多并不是必须启动的,根据业务需求可以去掉一些,本过程涉及到的文件:

     

    system/core/rootdir/init.rc

     

    frameworks/base/services/java/com/android/server/SystemServer.java

     

    3.  精简预装的apk文件

     

    系统启动过程中,会扫描系统指定目录下的所有apk文件,这个过程也是非常耗时的,预装的apk文件越少,系统启动速度也就越快,因此,精简预装apk也是优化系统启动速度最重要的手段之一。

     

    要想减少预装的apk文件,则需要分析系统的build文件,将不需要的apk编译选项删除掉,本过程涉及到的文件:

     

    build/target/product/xxxx.mk

     

    device/<company>/<product>/xxxx.mk

     

    vendor/..../xxxx.mk

     

    4.  减少内核的log打印级别

     

    过多的log打印消息会显著地增加系统启动的时间,log打印级别有多处可以调整,推荐修改init.rc文件中的loglevel来改变log打印级别。

     

    system/core/rootdir/init.rc

     

    5.  其他优化手段

     

    上面介绍的都是最常用的优化手段,其实还有很多其他的方法,简单列举如下:

     

    (1) 优化启动动画,降低帧率和图片尺寸

     

    (2) 精简系统,减小boot.img文件大小,可以显著减少启动过程中加载和解压boot.img的时间

     

    (3) 预先创建一些目录和文件,而不是在init过程中创建

     

    (4) 其他……

     

    6.  小结

     

    这里我给出一位国外的高手优化的结果作为比较和参考(我的优化结果只提高了20%的启动速度,远没有达到他的效果):

    转:http://ticktick.blog.51cto.com/823160/1664754

     

    展开全文
  • 应用启动速度优化

    2019-10-10 14:33:11
    应用启动速度优化一般可以有以下几种方式: 启动页优化 第三方库懒加载 MultiDex优化: 介绍了两种方式,一种是直接在闪屏页开个子线程去加载dex,难维护,不推荐;一种是今日头条的方案,在单独一个进程加载dex...
  • 记一次JPA项目启动速度优化

    万次阅读 多人点赞 2020-07-21 22:37:16
    JPA项目启动速度优化,从原来的44s优化为27s。原因是项目改造初期引入了多余的方法,自己挖的坑还是要自己去填。
  • android开机启动速度优化

    热门讨论 2014-06-10 20:00:40
    因项目需要,综合网上资源,对android开机启动速度优化的一些总结
  • splash启动速度优化

    千次阅读 2015-07-24 11:10:06
    splash启动速度优化
  • 本篇文章给大家详细分析了阿里数据iOS端启动速度优化的知识点以及心得,对此有兴趣的朋友参考学习下吧。
  • Android性能优化之启动速度优化   Android app 启动速度优化,首先谈谈为什么会走到优化这一步,如果一开始创建 app 项目的时候就把这个启动速度考虑进去,那么肯定就不需要重新再来优化一遍了。这是因为在移动...
  • myeclise启动速度优化

    2009-11-14 13:51:54
    myeclise启动速度优化,轻松了解myeclise
  • 启动速度优化记录

    2019-01-17 11:30:50
    启动速度优化 初步测试 初步测试各个方法耗时: 序号 测试结果(ms) Freso 45 DownloadMannager 3 okCache 80 imageLoader 17 Bugly 40 LoginFromLocal 167 InitSobot 4 InitHpplay 57 ...
  • zynq QSPI启动速度优化

    千次阅读 2017-11-14 10:16:33
    zynq QSPI启动速度优化
  • 展讯 camera_启动速度优化
  • android启动速度优化

    2016-08-31 12:08:54
    Android 开机启动速度优化 一 在开机启动中,可以借助bootchart 工具分析android的启动过程。bootchart是一个用于linux启动过程性能分析的开源软件工具,在系统启动过程自动收集CPU占用率、进程等信息,并...
  • App启动速度优化

    2018-04-04 09:35:50
    App启动速度优化该部分来自与性能优化相关面试题六,该博主总结了常用的面试问题,并且都录制了视频进行详细讲解,强烈推荐找工作的朋友去看看。1、异步初始化Application是程序的主入口,特别是很多第三方SDK都会...
  • 前言 成为一名优秀的Android开发,需要一份完备的知识体系,在这里,让我们...下面,就让我们扬起航帆,一起来逐步深入探索Android启动速度优化的奥秘。 一、启动优化的意义 如果我们去一家餐厅吃饭,在点餐的...
  • 针对Android系统,几乎目前市面上的设备终端启动速度都在40s以上,明显满足车载系统平台启动速度的要求,本文将根据项目经过从针对各个部分系统启动速度优化方面进行说明,以及优化的原则问题。本文以MTK平台为例...
  • Android 启动速度优化工具介绍

    千次阅读 2017-09-04 16:12:54
    在Android 8.0上面,google进行了启动速度的优化,但是对于开发者来说...这边就介绍一个android启动速度优化的工具,bootchart。 bootchart在5.0的时候就以推出,但是现在的使用方式有了一些调整,下面就简单介绍一下.
  • Android App启动速度优化 主要分两步: 1. 找出启动过程中,在主线程上耗时的操作函数 2. 修改它,让它延时操作、或者运行在子线程 我觉得这里面最最主要的工作是第一点是,找出耗时的操作。 如何找到耗时的...
  • 这边就介绍一个android启动速度优化的工具,bootchart。 bootchart在5.0的时候就以推出,但是现在的使用方式有了一些调整,下面就简单介绍一下. 首先,bootchart在8.0上面已经编译进了boot的image中,需要我们...
  • APP优化 启动速度优化

    万次阅读 2017-06-23 10:40:48
    什么是Xposed Xposed是一款特殊的安卓应用,诞生于著名的XDA论坛,由Xposed框架和Xposed模块组成。 你可以把它看作是一部模块化手机,Xposed框架相当于手机的主体,而Xposed模块相当于模块化手机的诸如镜头模块、...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 4,765
精华内容 1,906
关键字:

启动速度优化