Android中有两个类可以做到动态加载:PathClassLoader和DexClassLoader。这两个类都是继承于BaseDexClassLoader。在了解这两个类之前需要知道的是,不管是哪个类实际上最终调用的都是经过Dalvik优化过的Dex,不管你是APK,DEX,或是JAR,最终在加载的时候Android都会再重新生成一个优化的Dex。
PathClassLoader只能加载已经安装到系统里面的APK文件(也就是/data/app目录里面的APK文件),加载其他位置的文件都会出现ClassNotFoundException。猜测原因:上文说到一个很重要的概念就是优化的Dex,既然会生成文件,那么肯定就需要一个目录去存放这个文件。PathClassLoader中没有指定这个目录的参数,也就是说PathClassLoader是指定了一个目录,而这个目录应该就是/data/dalvik-cache(系统安装时存放优化过Dex的路径),所以说无法加载未安装的APK文件。附上PathClassLoader的两个构造方法:
DexClassLoader和PathClassLoader的最大区别就是可以指定优化过Dex的路径。这个区别决定了DexClassLoader可以加载未安装的APK文件。在尝试加载类的过程中遇到了各种异常,大概分析一下:
文件的权限问题:需要在Mainfest.xml里面添加
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
如果需要删除文件等权限,还需要添加
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
读取APK中assets资源问题:调用父类ClassLoader的getResourceAsStream(String resName)这里要注意resName是带路径+文件名的完整名字,记得要从assets开始,比如我要读取assets目录下的a.xml,那么resName就是assets/a.xml。
优化的Dex存放目录问题:最好是调用Activity的getDir(“dex”,Context.MODE_PRIVATE)来获取优化的Dex目录。如果提示没有读写该文件夹的权限,那么请参照第一个问题。之前推荐使用getDir方法而不是自己随便指定一个文件夹的原因是,在4.2的系统里(其他版本不知道有没有这个情况),有可能会提示:dir not owned by the current user。我猜测可能是Android加强了用户权限问题吧,改用getDir方法以后问题解决。