插件化开发之-gradle分包

来源:互联网 发布:rsyslog linux 编辑:程序博客网 时间:2024/05/29 11:40

插件化开发的由来

android5.0之前,dalvik采用了一个short型数据来表示一个dex所含有的方法数个数,而short类型最大值为65535,因此方法数最大为65535.随着项目的不断增大,当项目中的方法数超过dalvik所能识别的最大方法数时,编译就会失败,为了解决这个问题,插件化开发就诞生了。

何为分包?

以下是没有进行分包的apk目录:
这里写图片描述
可以看到普通的apk目录中只含有一个classes.dex文件,这里面是项目的java代码部分。而之所以出现65535问题,其实就是因为classes.dex文件中的方法数过多,因此通过分包可以将一个classes.dex文件拆分为多个dex文件。
通过gradle分包之后:
这里写图片描述
通过gradle分包之后就会将classes.dex拆分为多个dex文件。

gradle分包流程

  1. 在build.gradle文件中加入依赖:compile 'com.android.support:multidex:1.0.1'(它有两个版本)
  2. 在build.gradle中加入:` defaultConfig {
    applicationId “com.testandroid”
    minSdkVersion 19
    targetSdkVersion 25
    versionCode 1
    versionName “1.0”

    *multiDexEnabled true*;//设置分包

    }`
    3.自定义一个Application,在attachBaseContext()中加入:

protected void attachBaseContext(Context base) {        super.attachBaseContext(base);        MultiDex.install(this);    }

或者将自定义Application直接继承MultiDexApplication;也或者不需要自定义Application,直接在配置文件中将设置:

<application     android:name="android.support.multidex.MultiDexApplication"        android:allowBackup="true"        android:icon="@mipmap/ic_launcher"        android:label="@string/app_name"        android:theme="@style/AppTheme" >

完成这四部,然后编译,就可以实现分包了。

android类加载机制

首先我们要知道android中类加载的机制,不同于java加载类,android中加载类主要类加载器及其结构关系如下:
图1:
这里写图片描述

类加载主要涉及到三个类加载器:BootClassLoader、DexClassLoader、PathClassLoader.

  • BootClassLoader:最顶级类加载器,由c++实现,跟java中的BootStrapClassLoader类似。
  • DexClassLoader : 加载路径需要在创建DexClassLoader时传入,也就是加载任何路径下的apk/dex/jar(即未安装的apk文件)
  • PathClassLoader : 加载/data/app目录下的apk文件,也就是加载已经安装好了的apk

android类加载器加载流程:加载一个类时,首先由PathClassLoader类加载器来加载,然后它会委托给它的父加载器BootClassLoader来加载,如果BootClassLoader没有找到加载对象,那么就由PathClassLoader来加载,如果它也没有找到家在对象,就会报出异常。

MultiDex动态加载分dex

上面我们知道通过分包后dex文件被拆分为多个dex,因此分包后主dex如何加载分dex中的文件是个问题,这里就是分包后的关键-动态加载分dex。
androidstudio通过gradle分包后,动态加载分dex主要依赖google提供的Multidex,它是android4.4之后引入的一个专门用来实现动态加载dex的。
查看图1我们知道:BaseDexClassLoader维护了一个pathList,它是一个DexPathList类型。BaseDexClassLoader.findClass()方法调用了pathList.findClass(),而DexPathList里面维护了一个Element[] dexElements,它存储了dex文件。再看pathList.findClass(),它里面遍历加载了dexElements。因此BaseDexClassLoader其实就是加载了dexElements。又因为PathClassLoader和DexClassLoader都是BaseClassLoader的子类,因此他们的findClass()其实都是在加载dexElements。所以 可以通过将DexClassLoader的加载路径加入到PathClassLoader中去,实现动态加载多个分dex。

而MultiDex的实现原理就是依照这个思路:首先通过反射得到pathList这个字段,然后通过get方法获取到pathList,然后继续通过反射得到dexElements属性,将dexElemnts路径用object[]存起来,最后将DexClassLoader的object[]合并到PathClassLoader的object[]中去。这样就实现了将DexClassLoader的加载路径加到PathClassLoader加载路径中去,因为DexClassLoader可以加载到分dex文件,因此当PathClassLoader尝试去加载时,就会加载到分dex。

原创粉丝点击