测量Android应用程序启动时间

33

如何最精确地测量Android应用程序的启动时间?

在这里,启动时间是指从以下两个时间点之间所经过的时间:

  1. 应用程序进程未运行
  2. 用户在启动器中单击应用程序图标
  3. 主要活动已完全初始化

因此,您需要以某种方式获取自JVM启动以来经过的时间并记录它。


我所指的启动时间是第2点和第3点之间的差异。这可能是1或者可能是-1。更严肃地说,您是在构建自己的固件还是尝试从存储环境中获取它?此外,这是开发时的事情还是生产运行时的问题? - CommonsWare
我希望能够在开发过程中跟踪不同设备和Android版本的启动时间。另一个原因是一些用户抱怨应用程序自上次更新以来启动变慢,因此看到数字会很好。当然,我可以简单地测量自onCreate()被调用以来的时间...但知道真正的启动时间感觉更好:) 它还使我能够说“这只会使启动时间减慢5%”,所以这不是什么大问题。 - fhucho
9个回答

19

我知道我回答晚了,不过这确切地回答了这个问题。

从Android 4.4(API级别19)开始,默认情况下,此信息将在Logcat中记录。Logcat包含一个输出行,其中包含一个名为Displayed的值。这个值代表启动进程和完成在屏幕上绘制相应activity之间经过的时间。

ActivityManager: Displayed com.android.myexample/.StartupTiming: +3s534ms

关键是要在正确的位置查找它-

如果您正在跟踪命令行或终端中的logcat输出,则寻找经过的时间就很简单。要在Android Studio中查找经过的时间,必须在logcat视图中禁用筛选器。禁用筛选器是必要的,因为此日志由系统服务器而不是应用程序本身提供。

这些摘录来自文档


3
这如何使您能够以编程方式报告启动时间? - Yash
不适用于API 22(5.1.1),至少对于三星SM-G800F无效。 - ThinkDeep
你有没有想过如何在另一个线程中初始化第三方库以减少应用程序启动时间的问题? - Rahulrr2602
有没有办法缩短另一个应用程序从冷启动的启动时间? - Atul Chaudhary

13
我将理解你的问题为“我的应用启动时间足够快吗?我该如何检查是否已尽力?”。
启动时间在很大程度上是一个虚假的指标,因为它会因设备和ROM而异。我猜你最感兴趣的是有多少代码需要执行很长时间,以及可能阻塞主线程的内容。
我发现最有效的方法是在应用程序启动时使用Traceview,然后查看方法执行的时间以及主线程上是否存在任何间隙。
开始跟踪:
public class MyApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        Debug.startMethodTracing("startup");
    }
}

停止跟踪:

@Override
public void onViewCreated(final View view, final Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    Debug.stopMethodTracing();
}

一旦收集到跟踪数据,您应该能够看到任何对启动时间产生重大影响的内容。在我的情况下,如下所示,UI线程上有一个大的间隙,导致其被阻塞。

main thread blocked

事实证明,Crashlytics和Coremetrics都需要调用randomUUID(),然后在各个线程之间进行同步并阻塞主线程。解决方案只是启动一个新线程来初始化Coremetrics代码。

这是我仅通过测量启动时间不会发现的问题,但实际上它使应用程序的“启动时间”加快了几百毫秒。

在为Coremetrics初始化启动单独的线程后,这是另一个快照:

main thread not blocked


你有没有想过如何在另一个线程中初始化第三方库以减少应用程序启动时间? - Rahulrr2602

9

请在adb shell中按照以下方式进行检查。

adb shell
adb logcat -b events | grep am_activity_launch_time

[Output]
01-01 12:32:53.469 1236 1262 I am_activity_launch_time: 
    [0,205360373,com.sec.android.app.clockpackage/.ClockPackage,378,**378**,0]

Remarks:
Launch time for Clock is 378ms.

4
在较新的设备上,ActivityManager的日志记录方式有所不同,因此请使用以下命令:"adb logcat -s ActivityManager:I | grep Displayed"。其结果会类似于"I/ActivityManager( 288): Displayed com.foo.bar/.main.MainActivity: +1s313ms"。 - cermak.cz

5

将整个onCreate()方法用TimingLogger包装起来。只需将以下代码放在开头:

TimingLogger timings = new TimingLogger(TAG, "methodA");

and this at the end:

timings.dumpToLog();

如果您想要在某个中间步骤停止计时,可以使用 timings.addSplit("name"); 获取到达该步骤所需的时间。

我不知道TimingLogger,谢谢你的提示。然而,这并不能测量用户启动应用程序和调用onCreate()之间的时间。 - fhucho

2

一种在安卓中展示启动时间的简单方法。

enter image description here

有时候logcat输出中的Displayed行会包含一个额外的总时间字段。例如:

ActivityManager: Displayed com.android.myexample/.StartupTiming: +3s534ms (total +1m22s643ms)

在这种情况下,第一次测量仅针对最先绘制的活动。
来源:初始显示时间

1

请使用SysTrace

同时,可以使用Trace类来测量部分内容的时间。

Trace.beginSection("name");
Trace.endSection();

这个YouTube视频也是一个快速入门。


1
我认为这已经被构建到Firebase控制台中了,现在在性能下面 在此输入图像描述 在此输入图像描述

1

可以使用以下代码实现时间跟踪:

覆盖你的 Application

public class CustomApplication extends Application {
    public final static long APP_START_TIME = System.currentTimeMillis();

    /**
     * Do all other application stuff
     */
}

在您的主要Activity中添加几行代码:
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        final View contentView = findViewById(android.R.id.content);
        contentView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                if (Build.VERSION.SDK_INT >= 16) {
                    contentView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
                } else {
                    contentView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
                }
                long launchTime = System.currentTimeMillis() - CustomApplication.APP_START_TIME;
                Log.e("TEST", "App launch time = " + launchTime);
            }
        });
    }
}

别忘了在Manifest中定义你的自定义应用程序:

<application
    android:label="@string/app_name"
    android:name=".CustomApplication" >

</application>

重要提示:在启动应用程序之前,您必须将其关闭,因为应用程序存储了跟踪初始时间的静态变量。


1
报告 onGlobalLayout 实际上是正确的措施。感谢分享。 - Yash

-1
一种可能的方法是在onCreate()方法的开始和结束时保存时间,然后将这些时间相减以获取初始化应用程序所需的时间。

1
很不幸的是,这并不能测量用户启动应用程序和onCreate()被调用之间的时间。 - fhucho

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接