Android平台类加载流程源码分析
来源:互联网 发布:淘宝v达人 编辑:程序博客网 时间:2024/06/02 02:54
前言
其实大家都知道的Android是使用Java作为开发语言,但是他使用的虚拟机却并不是传统的JVM,在4.4以前Android使用Dalvik虚拟机,之后使用ART(Android Runtime).
Dalvik和ART与传统的JVM不同的地方在于,为了更加高效的在移动终端运行,Google重新定义了一套Dalvik字节码,用于在Dalvik和ART虚拟机上运行.
因此如果你希望自己在本地生成的Java代码能够在Android机器上运行,就必须通过转码的形式生成一份Dex文件.
生成Dex文件
当我们完成Java代码的书写后,需要使用dx
命令将Java代码由javac生成的class文件编译为Android虚拟机可识别的dex文件.
编译命令如下
1 dx --dex --output 'dex' 'target'
其中dex代表将要输出的dex文件名,target代表用于作为输入的文件,可以为class或jar文件.
解压生成的dex文件后,你会发现一个叫做classes.dex的文件,是不是很眼熟? 在每个Android的APK中都会存在这么一个文件,他才是所有代码的集合,类似于class文件.
生成完了Dex文件,接下来,让我们看看如何在Android设备上运行它.
加载Dex文件
下面是一个Dex文件加载的Demo:
1 Context context = getBaseContext(); 2 DexClassLoader loader = new DexClassLoader("/sdcard/demo.jar", 3 context.getCacheDir().getAbsolutePath(), null, context.getClassLoader()); 4 try { 5 Class<?> clazz = loader.loadClass("com.kifile.sample.Sample"); 6 Object object = clazz.newInstance(); 7 Method method = clazz.getDeclaredMethod("println"); 8 if (method != null) { 9 method.invoke(object);10 }11 } catch (ClassNotFoundException e) {12 e.printStackTrace();13 } catch (InstantiationException e) {14 e.printStackTrace();15 } catch (IllegalAccessException e) {16 e.printStackTrace();17 } catch (NoSuchMethodException e) {18 e.printStackTrace();19 } catch (InvocationTargetException e) {20 e.printStackTrace();21 }
通过以上代码,能够从位于/sdcard/demo.jar的文件中读取出一个”com.kifile.sample.Sample”类,并生成实例,动态调用其内部的”println”方法.
类加载流程分析
说了这么多了,都是教大家怎么在Android下动态加载java文件,现在我们来深入了解一下Android的类加载流程.
传统Java类加载流程
首先对于我们先简单说一下传统的Java程序的类加载流程.
几乎每一个Java类进行加载的时候都是通过ClassLoader进行加载的,当涉及引用新的类时,系统会自动调用当前类的ClassLoader区加载新类.
在加载的时候,首先判断类有无加载,然后再从父ClassLoader中尝试加载Class(之所以优先从父ClassLoader加载,是为了方便其他的兄弟ClassLoader能够复用这个Class),当父ClassLoader也无法找到时,才通过findClass方法进行自查找.
Dex类加载流程
熟悉了这个之后,我们再来看看Android的类加载流程.
其实两者的基本流程都是类似的:在能够复用类的时候,尽量复用类,实在找不到Class,才自己去查找,但Android程序毕竟同普通的Java程序有所不同,
首先Android程序里所有组件的启动均在ActivityThread中执行,同时在ActivityThread中会拥有一个LoadedApk的对象,在LoadedApk对象中,保存了包相关的数据,例如Dex文件和资源文件存放地址.
当我们启动Application,Activity,Service等组件的时候,系统从LoadedApk中获取ClassLoader对象,然后通过loadClass的方式,加载类.
这个ClassLoader对象就是PathClassLoader,因此对于Android应用而言,他几乎所有的类都是通过PathClassLoader进行加载(除了诸如String,System等类,他们在Dalvik虚拟机创建时就注册了).
所以我们需要关心的就是PathClassLoader的加载流程,PathClassLoader与上面样例代码中的DexClassLoader一样继承自BaseDexClassLoader.
我们看看BaseDexClassLoader类加载器的加载流程图.
以上文件的源码路径分别为:
$ANDROID/libcore/dalvik/src/main/java/dalvik/system/BaseDexClassLoader.java $ANDROID/libcore/dalvik/src/main/java/dalvik/system/DexPathList.java $ANDROID/libcore/dalvik/src/main/java/dalvik/system/DexFile.java $ANDROID/art/runtime/native/dalvik_system_DexFile.cc $ANDROID/art/runtime/native/java_lang_VMClassLoader.cc
如上所示,当DexClassLoader需要加载类时,先通过VMClassLoader查询该类是否已经加载,如果尚未加载就通过创建时传入的dexPath地址获取到dex包路径,然后根据Dex包路径去实例化Class对象,并存入虚拟机中,然后返回.
当你成功的从ClassLoader获取到Class时,其实在dalvik_system_DexFile中已经将当前类放置到ClassLoader对应的一张Hash表中,便于你下次重新获取:
1 #$ANDROID/art/runtime/native/dalvik_system_DexFile.cc#DexFile_defineClassNative2 class_linker->InsertDexFileInToClassLoader(soa.Decode<mirror::Object*>(dexFile),3 class_loader.Get());
1 #$ANDROID/art/runtime/class_linker.cc#InsertDexFileInToClassLoader2 class_table->InsertWithHash(klass, hash);
当我们通过ClassLoader获取类时,通过以下代码,将ClassLoader本身传入本地代码块,从ClassLoader对应的Hash表中查询类是否已经定义.
1 protected final Class<?> findLoadedClass(String className) {2 ClassLoader loader;3 if (this == BootClassLoader.getInstance())4 loader = null;5 else6 loader = this;7 return VMClassLoader.findLoadedClass(loader, className);8 }
以此,Android就完成了他的类加载流程.
原文地址: http://blog.kifile.com/android/2015/11/10/dex_class_loader.html
- Android平台类加载流程源码分析
- Android 6.0 View加载流程源码分析
- Android Launcher加载流程源码分析
- android中jni加载流程源码分析
- Android Activty的加载过程 启动流程 源码分析
- Android加载通话记录流程分析
- Android加载通话记录流程分析
- WordPress源码分析:首页加载流程
- Hibernate_hibernate.cfg.xml加载流程源码分析
- Dubbo SPI组件加载流程源码分析
- require.js源码分析之加载流程
- View的加载流程源码分析
- Android源码分析实战之JNI so库加载System.loadLibrary流程分析
- Android关机流程源码分析
- Android关机流程源码分析
- Android关机流程源码分析
- Android关机流程源码分析
- Android Handler 源码流程分析
- 【uploadify】初始化请求当前页错误解决
- OpenSSl 生成证书
- 详解Linux-I2C驱动
- Linux下基于Maven的自动化打包发布项目
- C语言实现单链表节点的删除(不带头结点)
- Android平台类加载流程源码分析
- 腾讯后台开发面试题及答案
- 作业day08
- libsqlite3.dylib找不到
- redis内部数据结构--简单动态字符串sds
- RxJava 转换操作符groupBy
- 推荐提升 Android 性能的建议
- IOS学习 NSNavigationController 多个子页面间相互跳转
- iOS清除缓存