Android5.0以下MultiDex下启动丝般柔滑

使用MultiDex官方解决方案

  1. minSdkVersion >=21: 只需要添加multiDexEnabled true就OK了,其他的不用瞎搞搞
    android {
        defaultConfig {
            ...
            minSdkVersion 21 
            targetSdkVersion 26
            multiDexEnabled true //只要添加这行就万事大吉,一马平川了
        }
        ...
    }
    
  2. minSdkVersion <21: 那就要稍微麻烦点
    • 如上述第1条一样,添加multiDexEnabled true
    • compile 'com.android.support:multidex:1.0.1'
    • 使用MultiDexApplication或者在自定义application中添加Multidex.install(this);如下所示
      public class MyApplication extends SomeOtherApplication {
          @Override
          protected void attachBaseContext(Context base) {
              super.attachBaseContext(context);
              Multidex.install(this);
          }
      }
      

minSdkVersion<21情况下遇到的坑

  1. Android5.0及以上的设备还好,Multidex.install(this);并不会占用多少时间,基本上都是秒执行的,因为Android5.0及以上的设备在安装apk的时候就优化好了Multidex,所以在首次打开的时候执行,Multidex.install(this);并不会占用多少时间
  2. 但是在Android5.0以下的设备下,Multidex.install(this);却花费好几秒的时间(在我的程序中花费了4秒左右),意味着软件首次打开至少要白屏4秒才能进入首页(先把鞋子放下,当然有解决方案,在后面)
  3. 在性能更弱的手机中,Multidex.install(this);执行的时间更长,有一定的几率出现ANR(毕竟在主线程执行了这么长时间)

分析

  1. Android5.0以下设备中Multidex.install(this)肯定是要执行的,要不然不能加载除主Dex之外的其他Dex文件
  2. 既然在主线程中执行会出现ARN,那就在新进程里初始化呗.

解决

  • MyApplication.class
    override fun attachBaseContext(base: Context?) {
        super.attachBaseContext(base)
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP && TextUtils.equals(applicationContext?.packageName, processName)) {
            val multiDexPreference = getSharedPreferences("MultiDexPreference", Context.MODE_PRIVATE)
            if (multiDexPreference.getString(BuildConfig.VERSION_NAME, "") != the2thDexSHA1) {//没有优化过multiDex
                val lock = java.lang.Object()
                thread {
                    Looper.prepare()
                    val handler = object : Handler(Looper.myLooper()) {
                        override fun handleMessage(msg: Message?) {
                            super.handleMessage(msg)
                            synchronized(lock) {
                                lock.notify()
                                multiDexPreference.edit().putString(BuildConfig.VERSION_NAME, the2thDexSHA1).apply()
                                if (null != Looper.myLooper()) Looper.myLooper().quit()
                            }
                        }
                    }
                    startService( //开启新进程初始化multiDex
                            Intent(applicationContext, MultiDexService::class.java)
                                    .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
                                    .putExtra("MESSENGER", Messenger(handler))
                    )
                    Looper.loop()
                }
                synchronized(lock) {
                    try {
                        lock.wait(30000)
                    } catch (e: InterruptedException) {
                        e.printStackTrace()
                    }
                }
            }
        }
        if (!processName.endsWith("multiDex")) {
            //如果是Android5.0以下的设备,执行到这里说明已经在其他进程初始过MultiDex了,再次执行不会消耗多少时间
            MultiDex.install(this)
        }
    }
    
    private val the2thDexSHA1: String? by lazy {
        val ai = applicationInfo
        val source = ai?.sourceDir
        try {
            val jar = JarFile(source)
            val mf = jar.manifest
            val map = mf.entries
            val a = map["classes2.dex"]
            a?.getValue("SHA1-Digest").toString()
        } catch (e: Exception) {
            e.printStackTrace()
        }
        null
    }
    
  • MultiDexService.class
    class MultiDexService : IntentService("MultiDexService") {
        override fun onHandleIntent(intent: Intent?) {
            val messenger: Messenger? = intent?.getParcelableExtra("MESSENGER")
            MultiDex.install(application)
            messenger?.send(Message())
            android.os.Process.killProcess(android.os.Process.myPid())
    
        }
    }
    
  • AndroidManifest.xml
    <service
            android:name=".MultiDexService"
            android:process=":multiDex" />
    

小小结

  • 如此一来,就避免了低端机型上的ARN了,至少不会死了...

新坑&分析

  • 但是软件打开后还是会有很长时间的白屏/黑屏,一点都不丝般柔滑
  • 这个坑简单,只要设置LaunchActivitytheme就行,设置windowBackground默认壁纸

丝般柔滑解决方案

  • style
    <style name="splashTheme" parent="Theme.AppCompat.NoActionBar">
        <item name="android:windowBackground">@drawable/splash_placeholder</item>
    </style>
    
  • drawable/splash_placeholder
    <?xml version="1.0" encoding="utf-8"?>
    <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
        <item android:drawable="@color/normal_background_color" />
        <item>
            <bitmap
                android:src="@drawable/ic_launcher" />
        </item>
    </layer-list>
    
  • AndroidManifest.xml,修改theme如下例子
    <activity
            android:name=".LauncherActivity"
            android:theme="@style/splashTheme">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
    </activity>
    

小结

这下就能丝般柔滑了

参考

必知必会 | Android 性能优化的方面方面都在这儿 @鸿洋
Android MultiDex初次启动APP优化
其实你不知道MultiDex到底有多坑

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

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 172,062评论 25 707
  • 写在前面 前几天,开发中遇到一个问题,Log信息如下: 从报错信息来看,是没有找到DateTakenCompara...
    ConnorLin阅读 21,072评论 2 34
  • 昨天健身教练跟我说,要我每天早起快走15分钟 我六点半准时迎着太阳起来,喝完水下楼 楼下有很多老爷爷老奶奶,年轻人...
    袁慧_3c1b阅读 126评论 0 0
  • 一、 早晨,我突然宣布一件让我自己都不敢相信的事:我要去剪短...
    不爱叫的猫阅读 243评论 0 0
  • 今天是11月25曰,天气多云天空雾蒙蒙的,气温零下二零度,冻得人直搓手,中午时分太阳从云层钻出,人顿时觉得暖和了不...
    S三叶草s阅读 427评论 0 0