栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

几乎包含了市面上所有启动优化方案,Android原生开发如何深入进阶

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

几乎包含了市面上所有启动优化方案,Android原生开发如何深入进阶

从点击应用图标到UI界面完全显示且用户可操作的全部过程。

特点

耗时最多,衡量标准

启动流程

Click Event -> IPC -> Process.start -> ActivityThread -> bindApplication -> LifeCycle -> ViewRootImpl

热启动

因为会从已有的应用进程启动,所以不会再创建和初始化Application,只会重新创建并初始化Activity。

特点

耗时较少

启动流程

LifeCycle -> ViewRootImpl

ViewRootImpl

ViewRoot是GUI管理系统与GUI呈现系统之间的桥梁。每一个ViewRootImpl关联一个Window,

ViewRootImpl最终会通过它的setView方法绑定Window所对应的View,并通过其performTraversals方法对View进行布局、测量和绘制。

三、启动耗时检测 1、查看Logcat

在Android Studio Logcat中过滤关键字“Displayed”,可以看到对应的冷启动耗时日志。

2、adb shell

使用adb shell获取应用的启动时间

// 其中的AppstartActivity全路径可以省略前面的packageName
adb shell am start -W [packageName]/[AppstartActivity全路径]

执行后会得到三个时间:ThisTime、TotalTime和WaitTime,详情如下:

ThisTime
最后一个Activity启动耗时。

TotalTime
所有Activity启动耗时。

WaitTime
AMS启动Activity的总耗时。

一般查看得到的TotalTime,即应用的启动时间,包括创建进程 + Application初始化 + Activity初始化到界面显示的过程。

特点:

1、线下使用方便,不能带到线上。
2、非严谨、精确时间。

3、代码打点(函数插桩)

可以写一个统计耗时的工具类来记录整个过程的耗时情况。

其中需要注意的有:

在上传数据到服务器时建议根据用户ID的尾号来抽样上报。
在项目中核心基类的关键回调函数和核心方法中加入打点。

代码如下:


public class TimeMonitor {

private final String TAG = TimeMonitor.class.getSimpleName();
private int mMonitord = -1;

// 保存一个耗时统计模块的各种耗时,tag对应某一个阶段的时间
private HashMap mTimetag = new HashMap<>();
private long mStartTime = 0;

public TimeMonitor(int mMonitorId) {
Log.d(TAG, "init TimeMonitor id: " + mMonitorId);
this.mMonitorId = mMonitorId;
}

public int getMonitorId() {
return mMonitorId;
}

public void startMonitor() {
// 每次重新启动都把前面的数据清除,避免统计错误的数据
if (mTimetag.size() > 0) {
mTimetag.clear();
}
mStartTime = System.currentTimeMillis();
}


public void recordingTimetag(String tag) {
// 若保存过相同的tag,先清除
if (mTimetag.get(tag) != null) {
mTimetag.remove(tag);
}
long time = System.currentTimeMillis() - mStartTime;
Log.d(TAG, tag + ": " + time);
mTimetag.put(tag, time);
}

public void end(String tag, boolean writeLog) {
recordingTimetag(tag);
end(writeLog);
}

public void end(boolean writeLog) {
if (writeLog) {
//写入到本地文件
}
}

public HashMap getTimetags() {
return mTimetag;
}
}

为了使代码更好管理,定义一个打点配置类:


public final class TimeMonitorConfig {

// 应用启动耗时
public static final int TIME_MONITOR_ID_APPLICATION_START = 1;
}

因为,耗时统计可能会在多个模块和类中需要打点,所以需要一个单例类来管理各个耗时统计的数据:


public class TimeMonitorManager {

private static TimeMonitorManager mTimeMonitorManager = null;
private HashMap mTimeMonitorMap = null;

public synchronized static TimeMonitorManager getInstance() {
if (mTimeMonitorManager == null) {
mTimeMonitorManager = new TimeMonitorManager();
}
return mTimeMonitorManager;
}

public TimeMonitorManager() {
this.mTimeMonitorMap = new HashMap();
}


public void resetTimeMonitor(int id) {
if (mTimeMonitorMap.get(id) != null) {
mTimeMonitorMap.remove(id);
}
getTimeMonitor(id);
}


public TimeMonitor getTimeMonitor(int id) {
TimeMonitor monitor = mTimeMonitorMap.get(id);
if (monitor == null) {
monitor = new TimeMonitor(id);
mTimeMonitorMap.put(id, monitor);
}
return monitor;
}
}

主要在以下几个方面需要打点:

应用程序的生命周期节点。
启动时需要初始化的重要方法,如数据库初始化,读取本地的一些数据。
其他耗时的一些算法。

例如,启动时在Application和第一个Activity加入打点统计:

Application

@Override
protected void attachbaseContext(Context base) {
super.attachbaseContext(base);
TimeMonitorManager.getInstance().resetTimeMonitor(TimeMonitorConfig.TIME_MONITOR_ID_APPLICATION_START);
}

@Override
public void onCreate() {
super.onCreate();
SoLoader.init(this, false);
TimeMonitorManager.getInstance().getTimeMonitor(TimeMonitorConfig.TIME_MONITOR_ID_APPLICATION_START).recordingTimetag(“Application-onCreate”);
}

第一个Activity:

@Override
protected void onCreate(Bundle savedInstanceState) {
TimeMonitorManager.getInstance().getTimeMonitor(TimeMonitorConfig.TIME_MONITOR_ID_APPLICATION_START).recordingTimetag(“SplashActivity-onCreate”);
super.onCreate(savedInstanceState);

initData();

TimeMonitorManager.getInstance().getTimeMonitor(TimeMonitorConfig.TIME_MONITOR_ID_APPLICATION_START).recordingTimetag(“SplashActivity-onCreate-Over”);
}

@Override
protected void onStart() {
super.onStart();
TimeMonitorManager.getInstance().getTimeMonitor(TimeMonitorConfig.TIME_MONITOR_ID_APPLICATION_START).end(“SplashActivity-onStart”, false);
}

特点

精确,可带到线上,推荐使用。

注意

在上传数据到服务器时建议根据用户ID的尾号来抽样上报。
onWindowFocusChanged只是首帧时间,App启动完成的结束点应该是真实数据展示出来的时候,如列表第一条数据展示,记

《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》

【docs.qq.com/doc/DSkNLaERkbnFoS0ZF】 完整资料开源分享

得使用getViewTreeObserver().addonPreDrawListener(),它会把任务延迟到列表显示后再执行。

AOP(Aspect Oriented Programming)打点

面向切面编程,通过预编译和运行期动态代理实现程序功能统一维护的一种技术。

作用

利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合性降低,提高程序的可重用性,同时大大提高了开发效率。

AOP核心概念

1、横切关注点

对哪些方法进行拦截,拦截后怎么处理。

2、切面(Aspect)

类是对物体特征的抽象,切面就是对横切关注点的抽象。

3、连接点(JoinPoint)

被拦截到的点(方法、字段、构造器)。

4、切入点(PointCut)

对JoinPoint进行拦截的定义。

5、通知(Advice)

拦截到JoinPoint后要执行的代码,分为前置、后置、环绕三种类型。

准备

首先,为了在Android使用AOP埋点需要引入AspectJ,在项目根目录的build.gradle下加入:

classpath ‘com.hujiang.aspectjx:gradle-android-plugin- aspectjx:2.0.0’

然后,在app目录下的build.gradle下加入:

apply plugin: ‘android-aspectjx’
implement ‘org.aspectj:aspectjrt:1.8.+’

AOP埋点实战

JoinPoint一般定位在如下位置

1、函数调用
2、获取、设置变量
3、类初始化

使用PointCut对我们指定的连接点进行拦截,通过Advice,就可以拦截到JoinPoint后要执行的代码。Advice通常有以下几种类型:

1、Before:PointCut之前执行
2、After:PointCut之后执行
3、Around:PointCut之前、之后分别执行

首先,我们举一个小栗子:

@Before(“execution(* android.app.Activity.on**(…))”)
public void onActivityCalled(JoinPoint joinPoint) throws Throwable {

}

在execution中的是一个匹配规则,第一个*代表匹配任意的方法返回值,后面的语法代码匹配所有Activity中on开头的方法。

处理Join Point的类型:

1、call:插入在函数体里面
2、execution:插入在函数体外面

如何统计Application中的所有方法耗时?

@Aspect
public class ApplicationAop {

@Around(“call (* com.json.chao.application.baseApplication.**(…))”)
public void getTime(ProceedingJoinPoint joinPoint) {
Signature signature = joinPoint.getSignature();
String name = signature.toShortString();
long time = System.currentTimeMillis();
try {
joinPoint.proceed();
} catch (Throwable throwable) {
throwable.printStackTrace();
}
Log.i(TAG, name + " cost" + (System.currentTimeMillis() - time));
}
}

注意

当Action为Before、After时,方法入参为JoinPoint。
当Action为Around时,方法入参为ProceedingPoint。

Around和Before、After的最大区别:

ProceedingPoint不同于JoinPoint,其提供了proceed方法执行目标方法。

总结AOP特性:

1、无侵入性
2、修改方便

四、启动速度分析工具 — TraceView

使用方式

1、代码中添加:Debug.startMethodTracing()、检测方法、Debug.stopMethodTracing()。(需要使用adb pull将生成的**.trace文件导出到电脑,然后使用Android Studio的Profiler加载)

2、打开Profiler -> CPU -> 点击 Record -> 点击 Stop -> 查看Profiler下方Top Down/Bottom Up 区域找出耗时的热点方法。

Profile CPU

1、Trace types

Trace Java Methods

会记录每个方法的时间、CPU信息。对运行时性能影响较大。

Sample Java Methods

相比于Trace Java Methods会记录每个方法的时间、CPU信息,它会在应用的Java代码执行期间频繁捕获应用的调用堆栈,对运行时性能的影响比较小,能够记录更大的数据区域。

Sample C/C++ Functions

需部署到Android 8.0及以上设备,内部使用simpleperf跟踪应用的native代码,也可以命令行使用simpleperf。

Trace System Calls

检查应用与系统资源的交互情况。
查看所有核心的CPU瓶。
内部采用systrace,也可以使用systrace命令。

2、Event timeline

显示应用程序中在其生命周期中转换不同状态的活动,如用户交互、屏幕旋转事件等。

3、CPU timeline

显示应用程序实时CPU使用率、其它进程实时CPU使用率、应用程序使用的线程总数。

4、Thread activity timeline

列出应用程序进程中的每个线程,并使用了不同的颜色在其时间轴上指示其活动。

绿色:线程处于活动状态或准备好使用CPU。
黄色:线程正等待IO操作。(重要)
灰色:线程正在睡眠,不消耗CPU时间。

Profile提供的检查跟踪数据窗口有四种

1、Call Chart

提供函数跟踪数据的图形表示形式。

水平轴:表示调用的时间段和时间。
垂直轴:显示被调用方。
橙色:系统API。
绿色:应用自有方法
蓝色:第三方API(包括Java API)

提示:右键点击Jump to source跳转至指定函数。

2、Flame Chart

将具有相同调用方顺序的完全相同的方法收集起来。

水平轴:执行每个方法的相对时间量。
垂直轴:显示被调用方。

注意:看顶层的哪个函数占据的宽度最大(平顶),可能存在性能问题。

3、Top Down

递归调用列表,提供self、children、total时间和比率来表示被调用的函数信息。
Flame Chart是Top Down列表数据的图形化。

4、Bottom Up

展开函数会显示其调用方。
按照消耗CPU时间由多到少的顺序对函数排序。

注意点:

Wall Clock Time:程序执行时间。
Thread Time:CPU执行的时间。

TraceView小结

特点

1、图形的形式展示执行时间、调用栈等。
2、信息全面,包含所有线程。
3、运行时开销严重,整体都会变慢,得出的结果并不真实。

作用

主要做热点分析,得到两种数据:

单次执行最耗时的方法。
执行次数最多的方法。

五、启动速度分析工具 — Systrace

使用方式:

分享读者

作者2013年java转到Android开发,在小厂待过,也去过华为,OPPO等大厂待过,18年四月份进了阿里一直到现在。

被人面试过,也面试过很多人。深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,不成体系的学习效果低效漫长,而且极易碰到天花板技术停滞不前!

我们整理了一份阿里P7级别的Android架构师全套学习资料,特别适合有3-5年以上经验的小伙伴深入学习提升。

主要包括阿里,以及字节跳动,腾讯,华为,小米,等一线互联网公司主流架构技术。如果你有需要,尽管拿走好了。

35岁中年危机大多是因为被短期的利益牵着走,过早压榨掉了价值,如果能一开始就树立一个正确的长远的职业规划。35岁后的你只会比周围的人更值钱。

方法。
执行次数最多的方法。

五、启动速度分析工具 — Systrace

使用方式:

分享读者

作者2013年java转到Android开发,在小厂待过,也去过华为,OPPO等大厂待过,18年四月份进了阿里一直到现在。

被人面试过,也面试过很多人。深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,不成体系的学习效果低效漫长,而且极易碰到天花板技术停滞不前!

我们整理了一份阿里P7级别的Android架构师全套学习资料,特别适合有3-5年以上经验的小伙伴深入学习提升。

主要包括阿里,以及字节跳动,腾讯,华为,小米,等一线互联网公司主流架构技术。如果你有需要,尽管拿走好了。

[外链图片转存中…(img-tdPbmF8D-1640325285878)]

35岁中年危机大多是因为被短期的利益牵着走,过早压榨掉了价值,如果能一开始就树立一个正确的长远的职业规划。35岁后的你只会比周围的人更值钱。

本文已被CODING开源项目:《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》收录

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/678478.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号