实战系列——听说可以做到APP秒开?

不知道哪天下午,老板走到你面前;拿着手机看着你的编辑器:小王啊,你这个App启动有点慢啊,能不能优化一下呀?

小王:老板你可别乱说啊,我启动的时候可不慢啊,说着拿着手机打开App,老板你看,1、2、3、4、5、6、7s过去了...手机上的APP还停留在启动界面 (内心os,糟糕了),一阵虚汗袭来,对着老板:老板,启动界面请求接口太多啦,应该是网络慢的原因。。。

老板:我是用户,我不管你多少接口,我要的是快,你看别人家的APP,都是秒开、秒进;你怎么不行?

小王:.......

当然,上面的故事只是一种被老板加需求的情景;真实用户启动你APP非常慢的时候,多多少少会有抱怨,你可能会像我一样,打开浏览器一顿搜索:

启动优化搜索.png

然后一个个点进去查看后发现,一大堆理论:

1、主题页面(无法解决实际卡顿问题)
2、使用多线程异步初始化(实际项目多方SDK逻辑复杂)
3、使用 AppStartUp 初始化(实际上会遇到未初始化或初始化过慢的问题)

从来没有一个有解决自己项目中的优化点的文章,下面我从公司APP出发,从0开始优化,以肉眼能够看到的优化速度提供优化思路:

#从Debug.startMethodTracing()说起

做过性能优化的朋友都不会对Debug.startMethodTracing()方法陌生,这个方法可以生成对应的Trace文件,使用Profile可以用来分析CPU的方法运行耗时(在这里就不在演示生成和使用方法了);

但是现在当你搜索使用startMethodTracing生成TraceView文件的方法来检验耗时操作时;会发现谷歌提示你说已经过时了:

弃用Traceview.png

歇逼了,原来使用的方法不得行了,那按照谷歌推荐的方式来搞吧?但是之前使用Profile监视器可以看到一段时间内对应的CPU方法耗时,但是无法统计从点击应用图标开始的CPU耗时;

后面进入官网细心查看,我们可以看到Profile监视器其实是有这样的功能的:传送门

profile启动监视.png

## 使用Profile监视启动方法耗时

从上面的实践我们得知,可以通过设置Android Studio的启动来获取到Profile trace文件,具体的上图:

步骤
步骤一.png
步骤二.png
步骤三.png
步骤四.png

通过上面的步骤,Profile会自动生成启动的文件并开始分析,大概几十秒后,你会得到如下的界面:

启动后的界面.png

从左到右三个红框分别是:
1:得到的设备及文件
2:所有的线程运行耗时
3:分析后的方法或者时间图

### 分析

读者可能要发火了,废话说了一大堆,正事你是一件没干

稍安勿躁,前面一大堆铺垫都是为了分析启动后得到的文件,又因为每个应用的耗时和方法都不一样,我只是提供一种分析思路,而不是真正为你秒开(那你是标题党咯?)哈哈哈,能不能秒开当然得看各位看官的造化了...

首先,我们看下上面第三个红框里面分析的到底是什么:

Top Down
top_down.png

Top Down很明显是将所有的耗时从高到低排序,第一个native thread我们默认是没有trace的,因为是使用的 Trace Java Methods(细心的你不知道有没有注意到),如果没注意到,可以重新点进去Debug Configurations配置;

Flame Chart
flame_chart.png

这个图相信做过性能优化、内存优化的朋友都是非常熟悉的,我们经常查看CPU运行时间来查看方法耗时,看看对应的方法是否有优化空间;

Bottom Up
bottom_up.png

该方法是自底而上,我分析的过少,了解的可以留言;

从Flame Chart开始着手

打开页面,选中其中一个方格点击(不选中可能引起后面操作无法放大缩小),然后使用 WS缩放方格;

了解过应用启动过程的朋友可能知道,应用启动能够优化的过程仅在handleBindApplication之后,而第三方ContentProvider或者自己声明的Provider都会在Application#onCreate()方法之前运行,所以我们只需要看这一过程中运行的方法和耗时即可;
main函数耗时.png

从上面的方格可以看到有不同颜色的方法渲染,红色一般是指系统Room的方法,白色和黄色指自己的方法,这里自己是指厂商的room和APP业务代码

* 可以看 ① ② 处方法块中有白色块,但是看名字是`miui`厂商自己的代码,这一块方法我们是无法修改的

* 在调用handleBindApplication()方法里面,包括了:
   public void  handleBindApplication() {
      applyConfigurationToResourcesLocked();  // ①

      ...

      ContextImpl.createAppContext(this, data.info);  // ②


      ...

      
      installContentProviders(app, data.providers);  // ③


    ...
      mInstrumentation.callApplicationOnCreate(app);  // ④
   }

以上的方法在ActivityThread#handleBindApplication()方法中调用,当然我也是看到方法栈后省略了其中许多代码,原来的流程读者可以点到源码中细细品读;

① 按W放大方法栈,可以看到我当前项目中的MiuiResourcesImpl.updateConfiguration()方法栈无法优化,这是主题样式获取,系统在APP启动的时候设置的;

applyConfigurationToResourcesLocked.png

createAppContext()方法中调用了LoadedApk.crreateOrUpdateClassLoaderLocked,通过方法栈可以看到主要是获取到DexFile,而加载Dex文件也是一个耗时的过程,在了解到启动优化的时候,我们经常看到大厂有说到Dex优化,其实也是从这一过程着手

createAppContext.png

installContentProviders()该方法,使用过JetPack AppStartUp的都知道,其原理也是将初始化内容放到ContentProvider中,利用的就是ContentProvider初始化会比Application#onCnreate()早的原因,但是治标不治本,内容初始化还是在里面,耗时还是没减少;相反的,还可能引起未初始化就使用、或者初始化失败的情况;

installContentProviders.png

在这里就发现了问题,因为项目中使用了Mob Share SDK,而这个第三方库使用了一个ShareSDKFileProviderContentProvider,使用Mob也无需手动调用任何代码,原因是Mob插件帮我们完成了这一系列的操作;包括添加QQWechat依赖库还有MobSDK的初始化(初始化在MobProvider类中,这个MobProvider也在后面会初始化),看到Mob插件里面的功能,才知道插件原来功能这么强大;

当然,最新版本的Mob Share SDK我已经联系已经将Provider去除了,查看代码其实是使用的SSDKLog,对于耗时成本,日志对我们接入项目是完全没用的,所以后期版本考虑要去除调Mob(手动滑稽)

mob客服.png

callApplicationOnCreate()方法,调用了我们自己的Application,其中就是自己的业务耗时了;我们项目中用到了阿里ARouter友盟统计等第三方的初始化,可以尝试将ARouter异步初始化或者去除掉😹;

callApplicatoinOnCreate.png

####启动业务流程

一般App启动都会有一个启动页面、或者有一个广告页面,然后从启动页面到主页都会有一个;当我们从点击图标开始进入主页都会有自己的业务逻辑:

可能是调用服务器同步信息
可能是初始化第三方服务
也有可能是加载闪屏图片

我们项目从点击到主页的逻辑也非常多,包含了初始化第三方服务、调用接口、获取闪屏等等,所以从用户点击图标到进入主页的过程都需要各位自己去分析;
上面分析的步骤是从应用启动到Applicatoin#onCreate()方法的优化,可以看到哪些第三方耗时,进入onCreate()之后,就会调用ActivityThread#performLaunchActivity()启动我们的闪屏页面,当然也要分析这个过程的耗时;

缩小方法耗时栈,可以看到,在Application#onCreate()后调用了我们项目的StartActivity#oncreate()

startActivity.png

再次将焦点放大到StartActivity的耗时流程,看到各种熟悉的方法:
PhoneWindow.installDecor()
LayoutInflater.inflate()
loadXmlDrawable()

相信看到这些方法都不陌生,setContentView()的流程浮现在脑海中了吧~~ 但是回想起我的项目启动页面啥也没有,你居然给我耗时近1s时间,这肯定忍无可忍的;

既然io读写操作,xml的读写都是非常耗时的,那就直接使用代码创建界面吧,当然,越复杂的界面肯定优化效果越好,为了避免io操作,还是需要花时间精力改写;
xml 写法 代码写法
start_xml.png
start_java.png

当然,这是我们项目中的耗时,各位需花时间精力处理自己项目中的业务逻辑,这里就不再细究了;

总结

1、了解了谷歌废弃了Debug来生成Trace文件的方法,使用Profile来统计APP点击图标到启动的CPU耗时时间

2、知道了启动过程中哪些第三方库会导致应用启动慢,解决方法也简单,给第三方库提建议或者直接去掉那些耗时的第三方库

3、应用中的io操作必定是耗时的,应该避免这些操作,界面如有必要可以使用代码的方式创建;

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,491评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,856评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,745评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,196评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,073评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,112评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,531评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,215评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,485评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,578评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,356评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,215评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,583评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,898评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,497评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,697评论 2 335

推荐阅读更多精彩内容