性能优化中使用Profiler进行页面卡顿的排查及解决方式

本文介绍了Android应用性能优化中的页面卡顿排查方法,包括耗时操作监控、Profiler使用技巧,以及利用IdleHandler在空闲线程加载控件来减少主线程压力。还提到了相关工具如LeakCanary和Lint的使用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、前言

程序的优化在做过线上bug处理,布局层级优化,项目依赖库版本更新,重复库合并,删除未使用的资源,删除冗余的库,避免因为一个类而引入一个库的问题,leakcanary(参考链接:https://square.github.io/leakcanary/)内存检测处理,lint(参考链接:https://developer.android.google.cn/studio/write/lint?hl=zh-cn)静态代码检测后。如果想要继续优化,那么就需要使用其他工具了。比如开启严格模式StrictMode,该模式会将相关异常信息输出到控制台或者弹出对话框。亦或者使用Profiler等工具进行进行检测(需要注意的是Profiler只能解决一部分问题,不能解决所有问题)

需要注意的是本篇文章采用了Android Studio新版的UI进行操作,具体开启方式为Preferences->Appearance & Behavior ->New UI 。然后勾选Enable new UI并重启Android Studio。开发工具版本为

Android Studio Giraffe | 2022.3.1 Patch 4
Build #AI-223.8836.35.2231.11090377, built on November 14, 2023
Runtime version: 17.0.6+0-17.0.6b829.9-10027231 aarch64
VM: OpenJDK 64-Bit Server VM by JetBrains s.r.o.

目前为最新版本开发工具。
测试工具为红米K60,版本为Android13
据官方文档所说Profiler的工具监控UI在Android11、12、13上面的UI有不同的结果,这里需要注意版本不同带来的问题

如需打开 Profiler 窗口,请依次选择 View > Tool Windows > Profiler,或点击工具栏中的 Profile 图标 在这里插入图片描述

二、页面卡顿的排查方式

1、耗时操作的监控

可以选择采取以下方式启动应用
在这里插入图片描述
或者常规方式启动后使用以下方式打开监控工具
在这里插入图片描述
打开后选择CPU栏目打开
在这里插入图片描述
然后选择Java/Kotlin Method Sample (legacy)进行记录。Java/Kotlin Method Trace在测试时候记录的数据无法打开,所以没办法进行测试,后续可以打开的时候再进行尝试。需要注意的是对数据记录时间不能过长,否则会导致文件过大无法打开。所以只对关键操作进行记录分析即可。记录完后点击Stop进行完成分析
在这里插入图片描述
记录完成后会自动打开,效果如下
在这里插入图片描述
选择左侧main选项卡进行确定然后查看Flame Chart。结果如下
在这里插入图片描述

其中右侧火焰图的绿色格子的内容是开发者可以尝试修改的地方。调用顺序从上往下为,应用函数到系统函数的调用顺序,鼠标光标悬停在某个方格上面可以看到该函数调用时长。然后开发者可以根据此进行相关代码修改。当然即使如此能修改的绿色格子也不足十分之一。

2、页面卡顿的监控

这里选择System Trace进行记录
在这里插入图片描述
记录完后的页面如下
在这里插入图片描述
然后选择All Frames->Janky Frames
在这里插入图片描述
可以通过点击Frame Duration进行选择排序,查看耗时最长的Frame的ID,如果该选项卡下面没有内容,表示应用没有页面卡顿。根据此帧在左侧Janky Frames的选项卡中进行查找该帧。
在这里插入图片描述
锁定后按动键盘上的M键放大或者屏幕右上角的放大缩小按钮放大缩小。
然后可查看具体帧的渲染时间,当然不是所有帧都能提供有效信息,那么就只能针对可以修改的地方进行修改
在这里插入图片描述
Profiler本文只记录部分用法,其余用法需查看官网或自己研究

五、优化的几种手段

  1. 在线程空闲时候操作
    比如有时候某些控件加载耗时可以在其余组件加载完毕后再进行加载。
private static final String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Looper.myQueue().addIdleHandler(mKeepIdleHandler);
        Looper.myQueue().addIdleHandler(mOnlyOnceIdleHandler);
        findViewById(R.id.textView).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.e(TAG, " 按钮被点击了 ");
            }
        });
    }

    private MessageQueue.IdleHandler mKeepIdleHandler = new MessageQueue.IdleHandler() {
        @Override
        public boolean queueIdle() {
            Log.i(TAG, " mKeepIdleHandler queueIdle 被回调了 ");
            return true;
        }
    };

    private MessageQueue.IdleHandler mOnlyOnceIdleHandler = new MessageQueue.IdleHandler() {
        @Override
        public boolean queueIdle() {
            Log.i(TAG, "mOnlyOnceIdleHandler queueIdle 被回调了 ");
            return false;
        }
    };

参考链接: IdleHandler的使用及原理
2. 异步加载View,AsyncLayoutInflater原理。这样可以避免所有UI都在主线程绘制
https://blog.csdn.net/binzeefox/article/details/124168109

四、参考链接

  1. 应用性能指南
  2. 使用布局检查器和布局验证工具调试布局
  3. StrictMode
  4. 功耗优化 · 方案篇 · Android功耗优化指导规范
  5. Android Profiler
  6. UI空闲时回调-MessageQueue.IdleHandler
  7. 异步加载View,AsyncLayoutInflater原理
<think>好的,我现在需要帮用户解决Android中通知跳转到Activity启动时间慢的问题。首先,用户提到了性能优化、通知栏、跳转Activity、启动时间这些关键词,所以我得围绕这几个点来分析可能的原因和排查方法。 首先想到的是冷启动和温启动的区别。如果应用进程已经被杀死,从通知跳转时可能触发冷启动,这自然会比温启动慢。根据引用[1]提到的,保活可以减少Application创建和初始化的时间,所以进程存活情况可能是一个因素。需要检查应用进程是否存活,如果被杀,冷启动时间就会长。这时候可以通过查看日志或者使用adb命令来确认进程状态。 接下来,Application和Activity的初始化时间过长也是一个常见原因。如果Application的onCreate方法里做了太多初始化操作,或者目标Activity的onCreate加载了过多资源,比如布局复杂、主线程执行耗时操作等,都会导致启动延迟。这时候需要用工具来测量各部分耗时,比如Android Profiler的CPU记录,或者手动打点记录时间戳。 然后是主线程阻塞的问题。如果在启动过程中,主线程有IO操作、数据库查询、网络请求等,会直接导致界面卡顿。需要检查代码中是否有在主线程执行这些操作的情况,特别是第三方库的初始化是否放在了主线程。使用StrictMode可以帮助检测这类问题。 另外,布局复杂度和过度绘制也可能影响启动时间。如果目标Activity的布局层次太深,或者有太多View,测量和布局的时间就会增加。用Layout Inspector检查布局结构,简化层次,使用merge或ViewStub可能有帮助。同时,GPU过度绘制分析可以查看是否有不必要的绘制操作。 系统资源竞争也是一个可能性。当系统资源紧张时,比如内存不足或CPU被其他进程占用,跳转可能会变慢。需要观察跳转时系统的资源使用情况,看是否有异常的内存占用或后台进程消耗资源。 针对这些可能的原因,可以采取的排查步骤包括: 1. 使用工具测量启动时间,比如adb命令或者手动打点,确定耗时阶段。 2. 分析Application和Activity的生命周期方法,出耗时操作。 3. 检查主线程是否有阻塞,使用StrictMode和CPU Profiler。 4. 优化布局,减少层级和过度绘制。 5. 监控系统资源,排除外部因素影响。 最后,引用中的内容提到保活对启动速度有帮助,但高版本Android保活变难,所以可能需要优化启动过程本身,而不是依赖保活。同时,引用[3]提到性能优化要针对必需的部分,避免得不偿失,所以需要优先解决主要瓶颈。</think>### Android通知跳转Activity启动耗时长问题排查指南 #### 一、核心原因分析 1. **冷启动耗时** 当应用进程被系统回收后,从通知跳转会触发完整的冷启动流程,包含$Application$初始化、$Activity$创建等阶段。根据引用[1]的说明,冷启动需要完成资源加载、类初始化等操作,耗时通常比温启动多2-5倍[^1]。 2. **主线程阻塞** 常见于以下场景: - 目标$Activity$的$onCreate()$中执行数据库操作 - 解析复杂布局文件时触发过度测量/布局 - 同步执行网络请求或文件IO 3. **复杂布局渲染** 当目标$Activity$包含嵌套层级超过10层的布局时,测量阶段可能消耗超过16ms(即丢失1帧),导致跳转卡顿。 #### 二、专业排查方法 **1. 启动时间测量** ```shell # 使用adb命令测量冷启动时间 adb shell am start-activity -W -n com.example/.TargetActivity ``` 输出关键指标: ``` TotalTime: 系统创建进程到完成onResume()的总时间 WaitTime: 从startActivity到完成第一帧绘制的时间 ``` **2. 性能分析工具组合** - **Android Profiler** 通过CPU记录检查主线程阻塞点: $$ \text{主线程耗时} = T_{onCreate} + T_{onStart} + T_{onResume} $$ - **Systrace** 重点关注以下阶段: ```python # 示例事件轨迹 atrace.py -b 32768 -t 5 app am res sched view ``` ![示意图:Activity启动阶段的CPU调度情况] - **Layout Inspector** 分析目标Activity的布局复杂度,建议遵循: $$ \text{View层级} \leq 5,\quad \text{Measure次数} \leq 2 $$ **3. 代码级优化检测** ```java public class TargetActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder() .detectDiskReads().detectDiskWrites().penaltyLog().build()); // 检测主线程IO super.onCreate(savedInstanceState); setContentView(R.layout.complex_layout); // 布局复杂度检测点 } } ``` #### 三、优化实施路径 1. **启动模式优化** - 对通知跳转Activity使用$singleTop$启动模式 ```xml <activity android:name=".TargetActivity" android:launchMode="singleTop"/> ``` 2. **延迟初始化策略** ```java // 使用Jetpack Startup库进行初始化优化 AppInitializer.getInstance(context) .initializeComponent(HeavyLibraryComponent.class); ``` 3. **布局预加载技巧** 通过异步Inflate实现布局预加载: ```java ViewStub stub = findViewById(R.id.stub); stub.setLayoutResource(R.layout.heavy_layout); stub.inflateAsync(); ``` #### 四、进阶优化建议 - **类加载优化**:采用MultiDex分包加载策略 - **资源压缩**:使用WebP格式替代PNG,可减少30%解码时间 - **渲染优化**:对复杂列表使用RecyclerView的预取机制 $$ \text{预取量} = \frac{\text{屏幕高度}}{\text{Item高度}} + 2 $$
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值