Android启动速度优化

最近针对手上的项目做了一些Android App启动速度的优化,查阅了一些资料
影响启动速度的原因
高耗时任务
数据库初始化、某些第三方框架初始化、大文件读取、MultiDex加载等,导致CPU阻塞

复杂的View层级
使用的嵌套Layout过多,层级加深,导致View在渲染过程中,递归加深,占用CPU资源,影响Measure、Layout等方法的速度

类过于复杂
Java对象的创建也是需要一定时间的,如果一个类中结构特别复杂,new一个对象将消耗较高的资源,特别是一些单例的初始化,需要特别注意其中的结构

优化的案例如下:
Glide及其他框架
Glide是一个很好用的图片加载框架,除了常用的图片加载、缓存功能以外,Glide支持对网络层进行定制,比如换成OkHttp来支持HTTP 2.0。不过,如果在追求启动速度的情况下,在Splash页或主界面加载某一张图片时,往往是第一次使用Glide,由于Glide没有初始化,会导致这次图片加载的时间比较长(不管本地还是网络),特别是在其他操作也在同时抢占CPU资源的时候,慢的特别明显!而后面再使用Glide加载图片时,还是比较快的
解决方案:Application的onCreate方法中,在工作线程调用一次Glide.get(this)

@Override
public void onCreate() {
    super.onCreate();
    new Thread(new Runnable() {
        @Override
        public void run() {
            Glide.get(BaseApplication.this);
        }
    }).start();View和主题

View层级
主要在于首屏/Splash页的Layout布局层次过深,导致View在渲染时,递归加深,消耗过多的CPU和内存资源,阻塞主线程,所以最根本的思路就是解决层级问题,检查一个App的View层级,可以使用Android Studio自带的Layout Inspector工具,如图:


image.png

在选择了需要检查的进程及Window(Dialog可能会创建新的Window,但显示的Activity是同一个)以后,就可以看到Android Studio自动进行的Capture的内容了


image.png

根据左边View层级显示的内容,分析不必要的嵌套布局,通过改造,即可对View层级进行优化

当然优化布局文件外;我们还可以通过代码构建控件,由于加载解析xml文件也是耗时的

App主题
如果想提高APP的启动速度,尤其是使用Splash的App,务必将第一个Activity的主题设为FullScreen的,这样能有效提高启动速度;启动一个Activity的时候,系统会创建包含一个DecorView的Window,而StatusBar也好,ActionBar也好,都是这个View中的子元素,多了一个View,当然多了一层布局,肯定是耗时的
进一步优化
某些APP,如:微博,能够做到点了图标就立即做出响应,显示出它的Splash页
apktool一下微博的apk,可以发现微博对首页的主题背景,使用了一个drawable来实现

<!-- styles.xml -->
<style name="NormalSplash" parent="@android:style/Theme">
    <item name="android:windowBackground">@drawable/welcome_layler_drawable</item>
    <item name="android:windowNoTitle">true</item>
    <item name="android:windowContentOverlay">@null</item>
    <item name="android:scrollbarThumbVertical">@drawable/global_scroll_thumb</item>
    <item name="android:windowAnimationStyle">@style/MyAnimationActivity</item>
</style>

<!-- welcome_layler_drawable.xml -->
<?xml version="1.0" encoding="utf-8"?>
<layer-list
xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@id/welcome_background" android:drawable="@drawable/welcome_android" />
    <item android:bottom="@dimen/login_icon_padding_bottom">
        <bitmap android:gravity="bottom|center" android:src="@drawable/welcome_android_logo" />
    </item>
    <item android:top="@dimen/splash_slogan_margin_top">
        <bitmap android:gravity="center|top" android:src="@drawable/welcome_android_slogan" />
    </item>
    <item android:top="20.0dip" android:right="20.0dip">
        <bitmap android:gravity="center|right|top" android:src="@drawable/channel_logo" />
    </item>
</layer-list>

由此可见,使用layer-list的形式,可以使一系列的Bitmap按照类似View布局的形式来排布,通过将生成的drawable设置为background的形式,最终并不会生成任何View,极大程度减小View绘制占用的时间,提升启动速度!

对于多线程的思考
在App启动时,为了加快启动速度,通常会使用多线程手段来并行执行任务,充分发挥多核CPU的优势,提高运算效率。此方法固然能够对启动速度的优化,起到一定作用,但实际开发中,有以下几点值得深思:

并发的线程数,多少合适?(效率高但不至于阻塞)

频繁切换线程,是否带来负面影响?(频繁地从主线程扔进辅助线程操作再将结果抛回来会不会比直接执行更慢)

何时并行?何时串行?(有的任务能只能串,有的任务可以并行)

这个时候,拿Android经典的AsyncTask类来说事,再合适不过了!

private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
// We want at least 2 threads and at most 4 threads in the core pool,
// preferring to have 1 less than the CPU count to avoid saturating
// the CPU with background work
private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;

上面的代码是AsyncTask确定线程池数量的部分,其中,核心执行池保证最少2个线程,最多不超过CPU可用核数-1,最大线程池数量为CPU核数的2倍+1

这样配置线程池的目的很简单:防止并发过大,导致CPU阻塞,影响效率

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

推荐阅读更多精彩内容