Android 性能优化——APP启动优化

 一、APP启动流程

        首先在《Android系统和APP启动流程》中我们介绍了 APP 的启动流程,但都是 FW 层的流程,这里我们主要分析一下在 APP 中的启动流程。要了解 APP 层的启动流程,首先要了解 APP 启动的分类。

1、启动分类

冷启动

        应用从头开始启动,即应用的首次启动。需要做大量的工做,耗费的时间最多。

热启动

        当活动有驻留在内存中,系统只是把该活动放到前台,无需重复对象初始化、布局扩充和呈现。例如按了home键,相对于冷启动,开销较低。

温启动

        用户退出应用程序,随后又从新启动,可是活动的进程是有驻留在后台的。例如按了back键退出应用。

2、生命周期

冷启动

        对于冷启动的耗时计算比较复杂,除了 Activity 本身的生命周期外,还要考虑 Application onCreate 的耗时操作。所以对于冷启动来说,一般从进程创建(即 Application 的attachBaseContext 方法)开始计时,到完成视图的第一次绘制(即 Activity 的 onWindowFocusChanged 方法)停止计时。

        冷启动 Activity 生命周期:

onCreate() -> onStart() -> onResume() -> onWindowFocusChanged()

热启动

         相比于冷启动,热启动省去了 Application 的初始化,以及 Activity 的 onCreate。热启动生命周期:

Home:onPause() -> onStop()

热启动:onStart() -> onResume()

温启动 

        温启动生命周期:

Back:onPause() -> onStop() -> onDestory()

热启动:onCreate() -> onStart() -> onResume()

        可以看到温启动相比热启动,Activity 生命周期增加了一个 onCreate() 方法,在使用 Back 时也比 Home 多执行一个 onDestory()。

二、启动时间统计

1、埋点统计

        根据上面的生命周期,在不同方法中打印当前时间,通过查看 Log 计算不通启动方式的启动耗时。

2、查找Log

        通过查找 Log 关键字 Displayed 查看 APP 入口信息,即包含启动时间。

adb命令

adb logcat | grep "Displayed"

结果输出

I/ActivityManager( 384): Displayed com.test.myapp/com.test.myapp.MainActivity: 1734 ms (total 1734 ms)

3、adb命令统计

adb shell am start -W 包名/启动类的全限定名

实际使用

adb shell am start -W com.test.myapp/com.test.myapp.MainActivity

        冷启动需要杀掉最近任务进程,再使用上面的命令。热启动需要 Home 键退出应用后使用上面命令。

结果输出

Starting: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=com.test.myapp/.MainActivity }
Warning: Activity not started, its current task has been brought to the front
Status: ok
LaunchState: HOT
Activity: com.test.myapp/.MainActivity
ThisTime: 79
TotalTime: 79
WaitTime: 82
Complete

LaunchState:启动方式 COLD(冷启动)、 HOT(热启动)和 WARM(温启动)。

ThisTime:启动多个 Activity 的最后一个 Activity 的启动耗时。

TotalTime:启动多个 Activity 总耗时,包括新进程的启动和 Activity 的启动。也就是说,开发者一般只要关心 TotalTime 即可,这个时间才是自己应用真正启动的耗时。

WaitTime:应用进程的创建过程 + TotalTime,就是总的耗时,包括前一个应用 Activity pause 的时间和新应用启动的时间。

        如果只关心某个应用自身启动耗时,参考TotalTime;如果关心系统启动应用耗时,参考WaitTime;如果关心应用有界面Activity启动耗时,参考ThisTime。

多次测试

adb shell am start -S -R 10 -W com.test.myapp/com.test.myapp.MainActivity

        其中 -S 表示每次启动前先强行停止,-R表示重复测试次数,注意反斜杠、包名、类名。所以可以通过 -S 设置冷/热启动。

三、方法耗时统计

        traceview 统计可以用代码统计。也可以用 Android Studio自带的 cup profiler 来统计。

1、Debug Trace

@Override
public void onCreate() {super.onCreate();Debug.startMethodTracing("main_trace");……Debug.stopMethodTracing();
}

        生成文件路径:storage/emulated/0/Android/data/packagename/files/main_trace。

        然后直接将该文件拖入到 Android Studio 中,就能看到对应方法执行的时长,从而进行相关的优化,如是否可以在异步线程操作该方法或者考虑懒加载的方式,根据自己的业务找到合适的方法。

2、CPU Profiler

        Profiler 是 Android Studio 内置的工具。如下配置:

1)run -> edit configurations;
2)勾选start recording a method trace on startup;
3)从菜单中选择cpu记录配置(profiling菜单下勾选两个复选框);
4)apply --> profile模式部署。

详细使用参考:Android app的启动优化总结

3、systrace

@Override
public void onCreate() {super.onCreate();Trace.beginSection("Launcher");……Trace.endSection();
}

        命令行终端进入如下目录:

/Users/tian/Library/Android/sdk/platform-tools/systrace 

        输入如下命令进入监听状态:

    python systrace.py -o main_trace sched freq idle am wm gfx view binder_driver hal dalvik camera input res

        此时运行代码,完成之后在命令行窗口按 Enter 键结束监听,然后会生成目标文件 main_trace,同样使用 Android Studio 的 Profiler 工具进行分析。

三、优化策略

1、优化onCreate, onStart,onResume函数

        由于许多内容在 Activity 的 UI 初始化和生命周期中需要用到,所以大部分 Activity 中的成员需要在 onCreate 中通过 new 的方式赋值。这就要求 new 的类的构造函数应该尽可能简单,不要有耗时操作,以便快速执行。

        不要在这些函数中 new 暂时用不到的内容,比如一些提醒的 dialog,可以在需要提醒的地方再去创建。

2、优化布局文件

        减少UI的布局嵌套层数,从而减少 layout 时间。 简化XML布局,界面布局时,层次越多,加载的时间就越长。因此应该尽可能的减少布局层次。如果实在层次太多并且无法简化,建议不使用XML布局,直接在代码中进行布局。

        判断嵌套布局是否可以优化的方法:

1)借助工具Hierarchy Viewer,可以看到layout比较耗时的节点。

2)直接review xml布局文件。

        布局优化方案:

1)尽量使用 ConstraintLayout 和 RelativeLayout 替换 LinearLayout。

2)尽量为所有分辨率创建资源,减少不必要的硬件缩放,这会降低UI的绘制速度。

3)首次不需要显示的节点,尽量设置为GONE。

3、优化draw过程

        去掉不必要的背景,比如如果子节点和父节点size一样,那么父节点的background可以不设或者设为null。

        尽可能少用或者不用高质量图片,以提高运行效率。

4、优化数据访问

        有些属性需要在 onCreate 就获取,而这些属性保存在 ContentProvider 中。可以从下面两方面进行优化:

1)少用 cursor.getColumnIndex。可以在建表的时候用 static 变量记住某列的 index,直接调用相应index而不是每次查询。

2)查询时返回更少的结果集及更少的字段。只返回需要的字段和结果集,更多的结果集和字段会消耗更多的时间及内存。

5、优化自定义控件或UI部件

        自定义控件和UI部件,不管这些控件是否支持 xml 化,实现它们的代码质量很重要,要尽可能简化它们的构造过程。

6、代码方面的优化

1)使用缓存。尽量将需要频繁访问或访问一次消耗较大的数据存储在缓存中。

2)使用多线程。比较耗时的过程,尽可能的使用异步加载。避免UI主线程阻塞,发生长时间不响应。

3)只需要获取图片的高宽时,可以设置 InJustDecodeBounds 为 true。这样就不会去 decode 图片,减少了图片解析的时间。

4)判断语句如果较多时,尽量使用 switch..case..,而不是使用 if..else..。因为 if..else.. 是从上到下进行判断,而 switch..case.. 有对判断条件进行优化。

5)for() 循环中有 if() 判断,考虑实现为将 if() 判断语句放在 for() 语句外面,减少判断次数,for 语句可以快速执行。

6)String的拼接尽量使用io流。

7)数据类型和数据结构的选择。比如:hash 系列数据结构查询速度更优,ArrayList 存储有序元素。

7、延迟执行

        对于 onCreate, onStart,onResume 函数中的数据或变量初始化,不着急使用的可以放到使用时在进行初始化,或者放到子线程中处理。

8、空闲时间利用

        合理利用程序的空闲时间,等待页面都完全渲染完毕之后再执行。例如:使用IdleHandler,具体使用如下:

Looper.myQueue().addIdleHandler(new MessageQueue.IdleHandler() {@Overridepublic boolean queueIdle() {// 执行你的任务return false;}
});

        空闲时执行多个任务:

public class DelayTaskQueue {private final Queue<Runnable> mDelayTasks = new LinkedList<>();private final MessageQueue.IdleHandler mIdleHandler = () -> {if (mDelayTasks.size() > 0) {Runnable task = mDelayTasks.poll();if (task != null) {task.run();}}// mDelayTasks非空时返回ture表示下次继续执行,为空时返回false系统会移除该IdleHandler不再执行return !mDelayTasks.isEmpty();};public DelayTaskQueue addTask(Runnable task) {mDelayTasks.add(task);return this;}public void start() {Looper.myQueue().addIdleHandler(mIdleHandler);}
}

9、锁优化 

        锁是我们解决并发的重要手段,但是如果滥用锁的话,很可能造成执行效率下降,更严重的可能造成死锁等无法挽回的场景。

        当我们需要处理高并发的场景时,同步调用尤其需要考量锁的性能损耗:

1)能用无锁数据结构,就不要用锁。

2)缩小锁的范围。能锁区块,就不要锁住方法体;能用对象锁,就不要用类锁。

10、内存优化 

        内存优化的核心是避免内存抖动。不合理的内存分配、内存泄漏、对象的频繁创建和销毁,都会导致内存发生抖动,最终导致系统的频繁 GC。

1)解决应用的内存泄漏问题。这里我们可以使用LeakCanary 或者 Android Profile 等工具来检查我们查询可能存在的内存泄漏。平时编码应当注意避免内存泄漏。

2)如避免全局静态变量和常量、单例持有资源对象(Activity,Fragment,View等),资源使用完立即释放或者recycle(回收)等。

3)避免创建大内存对象,频繁创建和释放对象(尤其是在循环体内),频繁创建的对象需要考虑复用或者使用缓存。

4)加载图片可以适当降低图片质量,小图标尽量使用SVG,大图/复杂的图片考虑使用webp。尽量使用图片加载框架,如glide,这些框架都会帮我们进行加载优化。

5)避免大量bitmap的绘制。

6)避免在自定义View的onMeasure、onLayout和onDraw中创建对象。

7)使用 SpareArray、ArrayMap 替代 HashMap。

8)避免进行大量的字符串操作,特别是序列化和反序列化。不要使用+(加号)进行字符串拼接。

9)使用线程池(可设置适当的最大线程池数)执行线程任务,避免大量Thread的创建及泄漏。

11、线程优化

        当我们创建一个线程时,需要向系统申请资源,分配内存空间,这是一笔不小的开销,所以我们平时开发的过程中都不会直接操作线程,而是选择使用线程池来执行任务。所以线程优化的本质是对线程池的优化。

 12、IO优化

        IO优化的核心是减少IO次数。

网络请求优化

1)避免不必要的网络请求。对于那些非必要执行的网络请求,可以延时请求或者使用缓存。

2)对于需要进行多次串行网络请求的接口进行优化整合,控制好请求接口的粒度。比如后台有获取用户信息的接口、获取用户推荐信息的接口、获取用户账户信息的接口。这三个接口都是必要的接口,且存在先后关系。如果依次进行三次请求,那么时间基本上都花在网络传输上,尤其是在网络不稳定的情况下耗时尤为明显。但如果将这三个接口整合为获取用户的启动(初始化)信息,这样数据在网络中传输的时间就会大大节省,同时也能提高接口的稳定性。

磁盘IO优化 

1)避免不必要的磁盘IO操作。这里的磁盘IO包括:文件读写、数据库(sqlite)读写和SharePreference等。

2)对于数据加载,选择合适的数据结构。可以选择支持随机读写、延时解析的数据存储结构以替代 SharePreference。

3)避免程序执行出现大量的序列化和反序列化(会造成大量的对象创建)。

参考:Android APP启动速度优化

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/755050.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

windows查看局域网内所有已使用的IP IP扫描工具 扫描网段下所有的IP Windows环境下

推荐使用&#xff1a; Advanced IP Scanner 官网下载&#xff1a; https://www.advanced-ip-scanner.com/

sqllab第35-45关通关笔记

35关知识点&#xff1a; 宽字节注入数值型注入错误注入 payload:id1andextractvalue(1,concat(0x7e,database(),0x7e))0--联合注入 payload:id0unionselect1,database(),version()-- 36关知识点&#xff1a; 字符型注入宽字节注入错误注入 payload:id1%df%27andextractvalue(…

广州大彩科技新品发布:大彩科技COF系列2.4寸串口屏发布!

一、产品介绍 此次发布的是S系列平台2.4寸COF超薄结构串口屏&#xff0c;分辨率为240*320&#xff0c;该平台采用了Cortex-M3内核的处理器&#xff0c;内置了2Mbyte PSRAM和64Mbit FLASH&#xff0c;是专为小尺寸串口屏设计的MCU&#xff0c;精简了外围电路。 该平台默认支持大…

Docker 各种部署应用的详细参数

持续更新 Docker 部署pgsql命令 docker run -d \ --restartalways \ --name pgsql \ -v /data/apps/pgsql/data:/var/lib/postgresql/data \ -e POSTGRES_PASSWORDabc123 \ -p 15432:5432 postgres:14.10

开发常用的一些工具总结

开发常用的一些工具总结 记录一些常用的开发软件. Android 开发相关 : Android studio 安卓开发者必备的编辑器,也是我用过最好用的编辑器.还可以用来写JNI 和C.Android studio 插件 : GsonFormatLeakCanary 其他 VS Code :轻量级的开发工具,插件非常多,很好用,但是上手难度…

React+umi+dva 项⽬实战-lesson6

lesson4-react全家桶及原理解析.mov 项⽬实战 项⽬实战 课堂⽬标资源知识要点起步Generatorredux-sagaumi why umidvadva+umi 的约定安装Umi基本使⽤理解dva移动端cra项⽬简介课堂⽬标 掌握企业级应⽤框架 - umi掌握数据流⽅案 - dva掌握⽣成器函数 - generator掌握redux异步⽅…

青海200MW光伏项目 35kV开关站图像监控及安全警示系统

一、背景 随着我国新能源产业的快速发展&#xff0c;光伏发电作为清洁能源的重要组成部分&#xff0c;得到了国家政策的大力扶持。青海作为我国光伏资源丰富地区&#xff0c;吸引了众多光伏项目的投资建设。在此背景下&#xff0c;为提高光伏发电项目的运行效率和安全性能&…

【C++】堆区空间的申请和释放--- 2024.3.19

目录 C和C的区别&#xff08;申请堆区空间&#xff09;C中的new和delete结束语 C和C的区别&#xff08;申请堆区空间&#xff09; 在c语言中&#xff0c;在遇到需要申请一块堆区空间时&#xff0c;我们往往会使用malloc申请&#xff0c;使用free进行释放&#xff0c;但是为什么…

数据可信流通:从运维信任到技术信任

1.数据可信流通概念 "数据可信流通"通常指的是确保数据在不同系统、应用程序或者组织之间的传输和交换过程中的可信性、完整性和安全性。在数据流通的过程中&#xff0c;确保数据的真实性、完整性和保密性是非常重要的&#xff0c;尤其是涉及到敏感信息或者重要数据…

GateWay路由规则

Spring Cloud GateWay 帮我们内置了很多 Predicates功能&#xff0c;实现了各种路由匹配规 则&#xff08;通过 Header、请求参数等作为条件&#xff09;匹配到对应的路由 1 时间点后匹配 server:port: 8888 spring:application:name: gateway-servicecloud:nacos:discovery:…

使用verilog写一个模拟比特币挖矿游戏及testbench

设计模拟比特币挖矿游戏需要考虑到以下几个方面: 游戏目标和规则: 确定游戏的目标,例如挖取尽可能多的比特币或达到一定的挖矿目标。确定游戏的规则,例如通过计算难题来进行挖矿、使用特定的硬件设备等。确定状态及状态转移条件: 确定游戏中可能存在的状态,如等待开始、准…

Vue利用axios发送请求并代理请求

由于浏览器的同源策略&#xff0c;发送请求时常常遇到跨域问题&#xff0c;一种解决办法是让后端配置跨域&#xff0c;还有一种就是使用代理&#xff08;与前端工程一起启动&#xff0c;同一个端口&#xff09;&#xff0c;因为代理不是通过浏览器发送的&#xff0c;所以不受同…

蓝桥杯历年真题省赛java b组 2017年第八届 k倍区间

一、题目 k倍区间 给定一个长度为N的数列&#xff0c;A1, A2, ... AN&#xff0c;如果其中一段连续的子序列Ai, Ai1, ... Aj(i < j)之和是K的倍数&#xff0c;我们就称这个区间[i, j]是K倍区间。 你能求出数列中总共有多少个K倍区间吗&#xff1f; 输入 ----- 第一…

rust - 计算文件的md5和sha1值

本文提供了一种计算文件md5和sha1的方法。 添加依赖 cargo add file-hashing cargo add md-5 cargo add sha1添加功能函数 use file_hashing::get_hash_file; use md5::Md5; use sha1::{Digest, Sha1}; use std::io::Error; use std::path::Path;pub fn md5<P: AsRef<…

TEMU是什么?TEMU自养号测评有什么优势?

一、 TEMU是什么&#xff1f; TEMU是拼多多于海外线的跨境电商平台&#xff0c;“Temu”这个名字的含义也和拼多多的意思相近。Temu跨境电商自上线以来&#xff0c;下载量不断攀升&#xff0c;发展势头一片大好&#xff0c;击穿地板价的商品在欧美市场掀起了一阵狂潮&#xff…

[每日一氵] 双Ubuntu共享网络

以下是我的记录 两台Ubuntu&#xff0c;名为AB A机有两张网卡&#xff0c;其中一个网卡可上网&#xff0c;另一个空着B机有一张网卡 现在AB直连&#xff0c;假设 eth0 是A连接到互联网的接口&#xff0c;而 eth1 是要连接到服务器B的接口。 将两台服务器通过网线直接连接起…

【漫谈】叔本华:不能让自己的头脑成为别人思想的跑马场

1.说明 标题是我自己总结加上的&#xff0c;正文都是节选自《叔本华&#xff1a;怎样读书才有效》&#xff0c;不同版本翻译略有不同。 不能让自己的头脑成为别人思想的跑马场。 2. 节选 1. 有自己的思考 我们读书时&#xff0c;是别人在代替我们思想&#xff0c;我们只不过…

mysql虚拟列Generated Column

目录​​​​​​​ 1、Generated Column简介 生成的列定义具有以下语法&#xff1a; 2、实践 2.1 存储格式为json字段增加索引 2.2 手机号后四位 3、虚拟列索引介绍 3.1 虚拟列索引的限制 3.1.1 Virtal Generated Column 4、阿里云数据库环境是否支持 下期扩展&…

大话适航(一)民航产业

0. 前言 eVTOL、飞行汽车和低空经济已成为热门话题&#xff0c;政府引导资本投入新赛道&#xff0c;也势必会吸引跨界厂商前来淘金。只说民用航空器整机制造&#xff0c;技术最接近的行业是军工&#xff0c;然后是无人机&#xff0c;还有汽车、农业机械等。“互联网”曾经掀起…

数据库应用:Linux 部署 GaussDB

目录 一、实验 1.环境 2.Linux 部署 GaussDB 3.Linux 使用 GaussDB 4.使用 GaussDB 进行表与索引操作 5.使用 GaussDB 进行视图操作 6.使用 GaussDB 进行联表查询 7.使用 GaussDB 进行外键关联 二、问题 1.运行python脚本报错 2. 安装GaussDB 报错 3. install 安装…