Android中的类加载器
来源:互联网 发布:并发编程 多线程 区别 编辑:程序博客网 时间:2024/06/17 21:56
概述
在讲解类加载器之前,我们先看一张从Android项目打包成apk的一个过程
分类
Android 中有三个 ClassLoader, 分别为URLClassLoader、PathClassLoader、DexClassLoader。其中
- URLClassLoader 只能用于加载jar文件,但是由于 dalvik 不能直接识别jar,所以在 Android 中无法使用这个加载器。
- 它只能加载已经安装的apk。因为 PathClassLoader 只会去读取 /data/dalvik-cache 目录下的 dex 文件。例如我们安装一个包名为com.hujiang.xxx的 apk,那么当 apk 安装过程中,就会在/data/dalvik-cache目录下生产一个名为data@app@com.hujiang.xxx-1.apk@classes.dex的 ODEX 文件。在使用 PathClassLoader 加载 apk 时,它就会去这个文件夹中找相应的 ODEX 文件,如果 apk 没有安装,自然会报ClassNotFoundException
- DexClassLoader 是最理想的加载器。它的构造函数包含四个参数,分别为:
1.dexPath,指目标类所在的APK或jar文件的路径.类装载器将从该路径中寻找指定的目标类,该类必须是APK或jar的全路径.如果要包含多个路径,路径之间必须使用特定的分割符分隔,特定的分割符可以使用System.getProperty(“path.separtor”)获得.
2.dexOutputDir,由于dex文件被包含在APK或者Jar文件中,因此在装载目标类之前需要先从APK或Jar文件中解压出dex文件,该参数就是制定解压出的dex 文件存放的路径.在Android系统中,一个应用程序一般对应一个Linux用户id,应用程序仅对属于自己的数据目录路径有写的权限,因此,该参数可以使用该程序的数据路径.
3.libPath,指目标类中所使用的C/C++库存放的路径
4.classload,是指该装载器的父装载器,一般为当前执行类的装载器
为了便于大家理解,我截了一张图,展示了dexPath和libPath在Android中的路径
补充知识
由于Java的Runtime环境在初始化时内部会创建一个ClassLoader对象用于加载Runtime所需的各种Java类,所以一般不需要创建一个新的ClassLoader对象,而是使用当前环境已经存在的ClassLoader对象。
每个ClassLoader必须有一个父ClassLoader,在装载class文件时,子ClassLoader会先请求其父ClassLoader加载class文件,只有当父ClassLoader找不到class文件时,子ClassLoader才会继续装载该类
案例
下面我们通过一个例子来说明一下DexClassLoader的用法
假设有两个APK,一个叫app,一个叫Plugin,其中Plugin定义了一个PlugClass,该类中定义了一个函数function(),然后在app中我们去动态加载Plugin,调用它的function函数
public class PluginClass { private static final String TAG = "PluginClass"; public PluginClass(){ Log.d(TAG, "PluginClass: initialized"); } public int function(int a,int b){ return a+b; }}
同时我们给Plugin中的MainActivity定义一个Action
<activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN"/> <action android:name="com.intent.action.classloader"/> <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity>
然后我们编写app中的MainActivity如下
public class MainActivity extends AppCompatActivity { private TextView mTextView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mTextView = (TextView) findViewById(R.id.textview); testDexClassLoader(); } public void testDexClassLoader(){ //定义intent,指定的action要与plugin中的一致 Intent intent = new Intent("com.intent.action.classloader"); PackageManager packageManager = getPackageManager(); List<ResolveInfo> infos = packageManager.queryIntentActivities(intent, 0); ResolveInfo info = infos.get(0); ActivityInfo activityInfo = info.activityInfo; String packageName = activityInfo.packageName; Log.d(TAG, "testDexClassLoader: "+packageName);//com.example.plugin String sourceDir = activityInfo.applicationInfo.sourceDir; Log.d(TAG, "testDexClassLoader: "+sourceDir);// /data/app/com.example.plugin-1.apk String dataDir = getApplicationInfo().dataDir; Log.d(TAG, "testDexClassLoader: "+dataDir);// /data/data/com.example.host String nativeLibraryDir = activityInfo.applicationInfo.nativeLibraryDir; Log.d(TAG, "testDexClassLoader: "+nativeLibraryDir);// /data/app-lib/com.example.plugin-1 DexClassLoader classLoader = new DexClassLoader(sourceDir,dataDir,nativeLibraryDir,getClass().getClassLoader()); try { Class<?> aClass = classLoader.loadClass(packageName + ".PluginClass"); Object object = aClass.newInstance(); Method method = aClass.getMethod("function", new Class[]{Integer.TYPE, Integer.TYPE}); Integer result = (Integer) method.invoke(object, 3, 4); mTextView.setText(result+""); } catch (Exception e) { e.printStackTrace(); }}
我们看看运行的结果
接下来我们再看看PathClassLoader的用法
同样,我们在plugin中定义一个Animal类
public class Animal { public String sayHello(){ return "Hello"; }}
然后我们在app中编写如下代码
public class MainActivity extends AppCompatActivity { private static final String TAG = "MainActivity"; private TextView mTextView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mTextView = (TextView) findViewById(R.id.textview); testPathClassLoader(); } public void testPathClassLoader(){ String packageName = "com.example.plugin"; String classPath = "com.example.plugin.Animal"; try { ApplicationInfo applicationInfo = getPackageManager().getApplicationInfo(packageName, 0); String sourceDir = applicationInfo.sourceDir; Log.d(TAG, "testPathClassLoader: "+sourceDir);// /data/app/com.example.plugin-2.apk PathClassLoader pathClassLoader = new PathClassLoader(sourceDir,ClassLoader.getSystemClassLoader()); Class<?> aClass = Class.forName(classPath, true, pathClassLoader); Object object = aClass.newInstance(); Method method = aClass.getMethod("sayHello", null); String result= (String) method.invoke(object, null); mTextView.setText(result); } catch (Exception e) { e.printStackTrace(); } }}
总结
学习类加载器有什么用?
- 对Android工程的编译和打包进行自动化,比如建立每日构建系统,自动生成发布文件等
- 通过下载插件加载的方式实现功能扩展
- 有些功能性模块,或是第三方开发,或是分阶段开发的,为了方便程序的扩展,我们同样考虑将功能代码封装成插件的形式
0 0
- android中的类加载器
- android中的类加载器
- Android中的类加载器
- android中的类加载器,以及加载机制
- AsyncLoader - Android中的异步加载器
- Android 加载其他Apk中的类方法
- Android中的异步加载
- android中的异步加载
- Android中的图片加载
- Android中的动态加载
- Android类加载器
- Tomcat中的类加载器
- Java中的类加载器
- java中的类加载器
- Java中的类加载器
- java中的类加载器
- Java中的类加载器
- Java中的类加载器
- 5.1tcpdump抓包
- 【2016杭电女生赛1001】【C语言签到题】Solving Order
- 函数统计输入字符串中字母,数字等个数。
- C++——第六次作业。
- 使用JSP实现用户登录
- Android中的类加载器
- photoshop实现图片更换背景
- Ogre(1.9)的插件原理
- Spark函数讲解:cartesian
- 短信猫短信收发平台
- uBuntu make xconfig Linux内核配置 问题
- 课程练习三-1008-problem H
- NVIDIA详细解读游戏中DX9与DX11差别
- 【php】json对象解码为array数组