You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过自定义代码统计Android App精确启动时间并上报至Firebase

自定义统计Android App冷启动时间并上报Firebase

核心思路

通过记录两个关键时间点的差值获取精确启动时间:

  1. 应用进程启动的最早可捕获时间(用System.nanoTime()保证精度)
  2. 首个Activity界面完成绘制的时间

步骤实现

1. 记录进程启动起始时间

在自定义Application类中,用静态代码块记录进程启动的初始时间(静态代码块执行时机早于onCreate,更接近用户点击图标的时间点):

public class MyApp extends Application {
    public static long appStartTimeNanos;

    static {
        // 记录进程启动的纳秒级时间,不受系统时间调整影响
        appStartTimeNanos = System.nanoTime();
    }

    @Override
    public void onCreate() {
        super.onCreate();
        // 初始化Firebase相关组件(如未自动初始化)
        FirebaseApp.initializeApp(this);
    }
}

记得在AndroidManifest.xml中指定该Application:

<application
    android:name=".MyApp"
    <!-- 其他配置 -->
>

2. 捕获首个Activity绘制完成时间

在首个启动的Activity(如SplashActivity或MainActivity)中,监听根布局的绘制完成事件,计算启动耗时并上报:

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // 获取Activity的根视图
        View rootView = findViewById(android.R.id.content);
        rootView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                // 移除监听,避免布局变化重复触发
                rootView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
                
                // 计算启动耗时:纳秒转毫秒,方便阅读和存储
                long launchDurationNanos = System.nanoTime() - MyApp.appStartTimeNanos;
                long launchDurationMillis = TimeUnit.NANOSECONDS.toMillis(launchDurationNanos);
                
                // 上报到Firebase
                reportLaunchTime(launchDurationMillis);
            }
        });
    }

    private void reportLaunchTime(long durationMillis) {
        // 方案1:上报到Firebase Realtime Database(存储每条启动记录)
        DatabaseReference dbRef = FirebaseDatabase.getInstance().getReference("app_launch_metrics");
        String recordId = dbRef.push().getKey(); // 生成唯一记录ID
        if (recordId != null) {
            dbRef.child(recordId).setValue(new LaunchRecord(durationMillis, System.currentTimeMillis()));
        }

        // 方案2:上报到Firebase Analytics(用于聚合统计分析)
        Bundle eventParams = new Bundle();
        eventParams.putLong("launch_duration_ms", durationMillis);
        FirebaseAnalytics.getInstance(this).logEvent("custom_app_launch", eventParams);
    }

    // 用于Realtime Database的数据模型
    public static class LaunchRecord {
        public long durationMillis;
        public long timestamp;

        // Firebase需要空构造函数
        public LaunchRecord() {}

        public LaunchRecord(long durationMillis, long timestamp) {
            this.durationMillis = durationMillis;
            this.timestamp = timestamp;
        }
    }
}

关键注意事项

  • 区分启动类型:上述代码仅统计冷启动(进程完全新建)。若需统计热启动/温启动,可在Application中添加isAppInitialized静态变量,在onCreate中标记为true,在Activity中判断,若为已初始化状态,则改用Activity启动时间(如onCreate时的System.nanoTime())计算耗时。
  • 精度保障:始终使用System.nanoTime()计算时间间隔,避免System.currentTimeMillis()受系统时间调整的影响。
  • 避免重复上报:务必在onGlobalLayout回调中移除监听,防止因布局重绘重复触发上报逻辑。
  • 依赖配置:确保项目已添加Firebase相关依赖(如firebase-database、firebase-analytics),并完成Firebase控制台的项目配置。

内容的提问来源于stack exchange,提问作者lily

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 08:55:18