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
    
    

小小结

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

新坑&分析

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

丝般柔滑解决方案

  • style
    
    
  • drawable/splash_placeholder
    
    
        
        
            
        
    
    
  • AndroidManifest.xml,修改theme如下例子
    
            
                
                
            
    
    

小结

这下就能丝般柔滑了

参考

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

你可能感兴趣的:(Android5.0以下MultiDex下启动丝般柔滑)