跳至主要內容

Android 5.x 以下加载 MultiDex 白屏的处理优化

JI,XIAOYONG...大约 4 分钟android

当 APP 的 minSdkVersion 低于 Android 5 时,在方法数大于 65536 时,需要将 APP 打包为多个 DEX 文件,此时需要添加 MultiDex 依赖。

官方方法如下:

1.build.gradle

android {
    defaultConfig {
        ...
        minSdkVersion 15
        targetSdkVersion 28
        multiDexEnabled true
    }
    ...
}

dependencies {
  compile 'com.android.support:multidex:1.0.3'
}

2.MyApplication

方式❶:
public class MyApplication extends MultiDexApplication { ... }

方式❷:
public class MyApplication extends SomeOtherApplication {
  @Override
  protected void attachBaseContext(Context base) {
     super.attachBaseContext(base);
     MultiDex.install(this);
  }
}

此外,为了避免一些启动期间需要的任何类未在主 DEX 文件中提供而导致java.lang.NoClassDefFoundError,还需要告诉 AS 将这些类添加到主 DEX 文件中:

3.build.gradle

android {
    buildTypes {
        release {
            ❶ multiDexKeepFile file('multidex-config.txt')multiDexKeepProguard('multidex-config.pro')
            ...
        }
    }
}
//multidex-config.txt
com/example/MyClass.class
com/example/MyOtherClass.class

//multidex-config.pro
-keep class com.example.MyClass
-keep class com.example.MyClassToo
-keep class com.example.** { *; } // All classes in the com.example package

但是在实际运行中,Android 4.x 的系统会在 APP 安装后第一次启动时,在MultiDex.install(this)方法中进行 DEX 文件合并优化等耗时操作(主线程),往往会持续数十秒以上,从而导致 APP 第一次启动时长时间白屏,十分影响体验。

查阅相应的资料后大体有以下几种方案

  1. 设置主 Activity 的背景为透明色

    这样当用户点击 APP 图标启动 APP 时,在主 Activity 启动之前看到的一直是桌面的样子而非白屏,但这只是一种障眼法,用户可能会以为系统卡顿,体验并不好。

  2. 在 Application 中检测到是第一次启动的话,新开一个进程并在其中进行MultiDex.install(this)

    这种方法在主进程启动时,检测到尚未进行 MultidexOpt,则阻塞当前进程,新开一个进程,在其中加载一个 Activity,并在后台进程运行MultiDex.install(this),当 MultidexOpt 完成后再关闭当前进程,返回主进程继续正常开启 APP。

    由于主进程被阻塞的同时成为了后台进程,所以也不会触发 ANR,此外子进程中的过渡 Activity 也只用到了基本的类,所以基本不用担心会触发java.lang.NoClassDefFoundError,而且过渡 Activity 可以展示进度、提示等用户友好的页面,相对来说体验也好了很多。

但是这种方法从子进程返回主进程涉及到进程间通信,以及主进程的主 Activity 启动时生命周期会出现异常 (异常 (onCreate() -> onStart() -> onResume() -> onPause()->onResume()),仍然不是很好的解决方法。

结合上述的分析后,可以看到这种问题的优化思路主要在于如何在避免java.lang.NoClassDefFoundError的同时,在后台可靠的通过MultiDex.install(this)执行 MultidexOpt 操作。

通过以上方案 1 和 2 的结合,可以有一个比较完美的解决方案:

  1. 方案 2 中在过渡 Activity 的后台线程进行 MultidexOpt 操作思路是正确的,但是不需要再单独开一个进程,我们完全可以将其当做主进程的第一个 Activity,等待 MultidexOpt 操作完成后再跳转到主 Activity 并 finish 掉本 Activity,这样主 Activity 的生命周期也不会受影响。
  2. 这种情况下在部分低端机上,过渡 Activity 到主 Activity 跳转时会出现短暂黑屏,我们可以在过渡页面将 Activity 切换动画设置为渐变效果,并将主 Activity 背景设置为透明,待主 Activity 完全加载好后再将背景切换为普通模式。

综上处理,我们的 Application 无需改动,甚至主 Activity 也可以不做改动,只需要添加一个过渡页面为启动 Activity,在其中后台进行 MultidexOpt,等 DEX 文件处理完毕后再加载主 Activity。对项目改动少并且逻辑较为简单。

注:

  1. MultiDexOpt 即执行MultiDex.install(getApplication());方法;
  2. 需要注意过渡 Activity 尽量少的使用类,并且要确保过渡 Activity 可能会调用到的类加载到了主 dex 文件中。

参考文档

配置方法数超过 64K 的应用open in new window

Android MultiDex 初次启动 APP 优化方案优雅的实现open in new window

MultiDex 深入学习open in new window

文章标题:《Android 5.x 以下加载 MultiDex 白屏的处理优化》
本文作者: JI,XIAOYONG
发布时间: 2019/08/10 11:39:00 UTC+8
更新时间: 2023/12/30 16:17:02 UTC+8
written by human, not by AI
本文地址: https://jixiaoyong.github.io/blog/posts/caa169b7.html
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 许可协议。转载请注明出处!
你认为这篇文章怎么样?
  • 0
  • 0
  • 0
  • 0
  • 0
  • 0
评论
  • 按正序
  • 按倒序
  • 按热度
Powered by Waline v2.15.8