背景说明
这篇文章可以看作是对MultiDex实践的一篇补充,更进一步的背景是对美团MultiDex实现的一些具体细节的一种实现方式。
同美团团队一样,在实现MultiDex时,同样遇到一个问题,那就是:部分在classes2.dex中的二级界面,首次启动时,如果classes2.dex尚未加载完,而这时用户操作了该二级界面,Crash!!是必然的!美团的那篇文章也讨论了这个问题,解决方法就是在操作二级界面Activity时,首先判断classes2.dex是否加载完毕,如果加载完毕,则直接启动该Activity,如果尚未加载完毕,则引入一个WaitActivity,在WaitActivity中阻塞等待classes2.dex加载完成,等dex2加载完毕之后再启动该二级界面Activity。
这么做肯定是没有问题的,但有一点就是,如果二级界面太多,每个调用的地方都去判断dex2是否加载完未免太麻烦,好在Framework告诉了我们答案!我们知道Activity是由ActivityThread通过Instrumentation来启动的,再进一步跟进去,我们发现ActivityThread中有一个mInstrumentation对象,该对象即是Instrumentation,进一步查看Instrumentation源码,发现其与Activity启动相关的方法有以下几个:execStartActivity, newActivity等等,于是,我们就可以在这里面做些手脚!怎么做?修改Instrumentation或者ActivityThread也未免显得太过幼稚了!那么How?
方法其实很简单:(1)自定义MyInstrumentation继承自Instrumentation;(2)通过放射方式在应用刚启动时以MyInstrumentation替换掉ActivityThread中的mInstrumentation,替换的时机最好实在Application.attachBaseContext()中。
自定义Instrumentation
首先自定义MyInstrumentation继承自Instrumentation,在newActivity中作判断该Activity是否加载完,代码如下:
有了这关键的一步,WaitActivity的实现细节这里就不作多述,有兴趣的可以私我!
注册MyInstrumentation
实现了MyInstrumentation,剩下的就是以MyInstrumentation替换掉系统的Instrumentation,实现如下:
至此,比较完备的MultiDex实现方式算是告一段落了,整个过程,给我最大的感受就是:Read the Fucking Source Code是多么重要!RTFSC过程中,不仅能学到别人代码的组织形式,更重要的是能够从根本上为解决某些问题提供思路!