首页 文章 精选 留言 我的

精选列表

搜索[android],共10000篇文章
优秀的个人博客,低调大师

Android 冷启动优化实战:从 3 秒到 800毫秒 的排查路径

# 线上反馈"App 打开慢"是最常见也最难量化的性能问题。这篇复盘一次真实优化过程:把冷启动从 3.1 秒压到 800ms 左右,方法比结果更值得抄。 ## 一、先把"冷启动"讲清楚 冷启动 = 进程不存在 → 启动进程 → 加载 Application → 创建首个 Activity → 首帧渲染完成。 三个关键节点: - **T0**:`am_proc_start` 系统开始拉进程 - **T1**:`Application.onCreate` 结束 - **T2**:首个 Activity `onWindowFocusChanged(true)` 触发 我们要压的是 T2 - T0。中间的每一步都可能是黑锅。 ## 二、测量:不测量的优化都是玄学 只信一种数据:`adb shell am start -W`。 ``` adb shell am start -W -n com.demo.app/.MainActivity ``` 输出里关注: - `ThisTime`:Activity 启动耗时 - `TotalTime`:包含 Application 的总耗时 - `WaitTime`:AMS 层的等待时间 再叠加代码内打点: ``` class App : Application() { override fun onCreate() { val t0 = SystemClock.elapsedRealtime() super.onCreate() // ... 初始化 val cost = SystemClock.elapsedRealtime() - t0 Log.i("Startup", "App.onCreate cost=${cost}ms") } } ``` Activity 侧用 `Choreographer.getInstance().postFrameCallback` 或者 `reportFullyDrawn()` 抓首帧。 ## 三、Application 层:三板斧 这轮优化里 Application 从 1.4s 降到 380ms,靠的是三件事。 ### 1. 分级初始化 把 SDK 按"必须同步"/"可延后"/"可后台"三类拆开: ``` override fun onCreate() { super.onCreate() // 必须同步 initCrashReport() initLogger() // 主线程 idle 后跑 Looper.myQueue().addIdleHandler { initAnalytics() initImageLoader() false } // 后台线程 Thread { initPushSDK() initABTest() }.start() } ``` 关键点:**IdleHandler 只跑主线程能容忍的活**,别把耗时 SDK 塞进去,否则只是把卡顿从启动挪到首屏交互。 ### 2. 延迟到首屏之后 用 `App Startup` 库或者手写 `ContentProvider` 触发器都行,核心是把非首屏依赖的初始化推到 Activity `onResume` 后: ``` class MainActivity : AppCompatActivity() { override fun onResume() { super.onResume() if (!inited) { window.decorView.post { initSecondaryModules() inited = true } } } } ``` ### 3. 干掉隐式 ContentProvider 初始化 第三方 SDK 常用 悄悄在启动阶段跑代码。检查方式: ``` adb shell dumpsys package com.demo.app | grep -A2 "Provider" ``` 看到不必要的 Provider,用 `tools:node="remove"` 关掉,然后手动懒加载: ``` ``` 这一步单独省了 220ms,很多 SDK 的 Provider 其实完全不需要跟启动绑定。 ## 四、首屏 Activity:布局和数据都要瘦 Application 优化到位后,Activity 那 900ms 就成了瓶颈。 ### 1. 布局层级和 measure/layout 用 Layout Inspector 或 `hierarchyviewer` 看首屏层级。这次踩到两个坑: - 一个 `ConstraintLayout` 里嵌了 5 层 `LinearLayout`,重构成扁平 Constraint 后省 90ms - `include` 了一个巨大的通用头部布局,里面 90% 视图 `visibility=gone`,改成 `ViewStub` 懒加载省 60ms ### 2. 主线程数据源要异步 首屏依赖的接口不要在 `onCreate` 里同步等。用 Flow + Loading 骨架屏: ``` class HomeViewModel : ViewModel() { val state = MutableStateFlow(UiState.Loading) init { viewModelScope.launch { state.value = try { UiState.Success(repository.load()) } catch (e: Exception) { UiState.Error(e) } } } } ``` Activity 侧先渲染骨架,数据回来再刷。用户感知的"启动完成"不是数据完成,是**首帧可见**。 ### 3. 主题闪屏别用 Activity 老代码里用 `SplashActivity` → `MainActivity` 跳转,光 Activity 创建就多花 150ms。改成 `Theme` 层的 `windowBackground`: ``` @drawable/launch_bg ``` MainActivity 用 Launcher 主题,`super.onCreate` 后立刻切回 AppTheme。省一个 Activity,稳赚。 ## 五、验证和防回归 优化完不做防回归,三个月后必然被打回原形。加两道闸: ### 1. CI 里加启动耗时基线 用 `am start -W` 跑 20 次,取 P90,超过基线 15% 直接失败。这套脚本可以放到 GitHub Actions 或 Jenkins。 ### 2. 线上监控 上报 `Application.attachBaseContext` 到 `onWindowFocusChanged` 的耗时,按机型分位统计。低端机 P90 才是真实体验,别只看平均值。 ``` object StartupTracker { private var t0 = 0L fun mark() { t0 = SystemClock.elapsedRealtime() } fun report(tag: String) { val cost = SystemClock.elapsedRealtime() - t0 Analytics.log("startup", mapOf("tag" to tag, "cost" to cost)) } } ``` ## 六、复盘:哪些是"看起来很美"的优化 有几种做法要谨慎: - **多 dex 优化 / MultiDex.install 提前**:现在 minSdk ≥ 21 基本不用管 - **StrictMode 关掉**:只是把问题藏起来,别关,改成 release 关 debug 开 - **反射调用系统 API 跳过初始化**:兼容性成本远大于收益 - **提前预加载类**:意义不大,dex2oat 之后差异不明显 真正立竿见影的还是那三件:**减少 Application 里的同步工作**、**首屏布局扁平化**、**用主题闪屏代替 SplashActivity**。 ## 小结 冷启动优化没什么魔法:测量 → 拆解 → 分级 → 防回归。别一上来就找玄学方案,先把 `am start -W` 跑起来,把 Application 里的初始化列个表,砍掉一半你就赢了一半。

资源下载

更多资源
优质分享App

优质分享App

近一个月的开发和优化,本站点的第一个app全新上线。该app采用极致压缩,本体才4.36MB。系统里面做了大量数据访问、缓存优化。方便用户在手机上查看文章。后续会推出HarmonyOS的适配版本。

Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

用户登录
用户注册