这两天研究android的动态加载,下面把心得和大家分享一下吧!
首先上一个实例:
这个是stackOverFlow上面的一个帖子,被采纳的答案解决了这个问题:
http://stackoverflow.com/questions/6857807/is-it-possible-to-dynamically-load-a-library-at-runtime-from-an-android-applicat
简单翻译一下:
第一步:
建一个普通的android项目,里面添加一个类:
01.
package
org.shlublu.android.sandbox;
02.
import
android.util.Log;
03.
publicclassMyClass{
04.
publicMyClass(){
05.
Log.d(MyClass.
class
.getName(),
"MyClass: constructor called."
);
06.
}
07.
public
void
doSomething(){
08.
Log.d(MyClass.
class
.getName(),
"MyClass: doSomething() called."
);
09.
}
10.
}
第二步:
把这个android项目导出为apk (当然也可以打成jar包,如果打成jar包,那么jar包里面必须包含classes.dex,这个classes.dex里面包含了上面的MyClass类)
第三步:
新建一个android项目(或者用刚刚那个也行)
在里面添加这样一个activity:
01.
public
class
Main
extends
Activity
02.
{
@SuppressWarnings
(
"unchecked"
)
03.
@Override
04.
protected
void
onCreate(Bundle savedInstanceState){
05.
super
.onCreate(savedInstanceState);
06.
setContentView(R.layout.main);
07.
try
{
08.
final
String libPath =Environment.getExternalStorageDirectory()+
"/shlublu.jar"
;
09.
final
File tmpDir = getDir(
"dex"
,
0
);
10.
final
DexClassLoader classloader =newDexClassLoader(libPath, tmpDir.getAbsolutePath(),
null
,
this
.getClass().getClassLoader());
11.
final
Class<Object> classToLoad =(Class<Object>) classloader.loadClass(
"org.shlublu.android.sandbox.MyClass"
);
12.
final
Object myInstance = classToLoad.newInstance();
13.
final
Method doSomething = classToLoad.getMethod(
"doSomething"
);
14.
doSomething.invoke(myInstance);
15.
}
catch
(Exception e){
16.
e.printStackTrace();
17.
}
18.
}
19.
}
第四步:
跑起来,进入上面的Main
查看Log看结果,是不是发现log里面已经有了我们刚刚第一步添加的MyClass中的方法了?
其实内容并不是很多,看代码基本上就可以看得懂。用到了一个类:
DexClassLoader. 这个类的功能是寻找apk, jar, zip等压缩包里面的classes.dex文件。并把它加载到classloader对象中。然后调用的时候,利用java类的反射功能就可以实现了。
我对java研究的比较少,略有知道java里面也有一个classLoader的类,在android中的classloader类是
BaseDexClassLoader, 它有两个派生类:
PathClassLoader和
DexClassLoader
这两个类有何区别?除了用法上的不同(可以见其构造方法),主要是适用范围不同:
PathClassLoader适用于那些已经安装好的apk包。在前面的博文
什么是
Android中的odex和deodex
中已经提到了一个目录,/data/dalvik-cache,这个目录里面包含了所有安卓已经安装的classes.dex文件。因此,如果使用PathClassLoader来加载类,最后加载完的类都会存在这个文件夹里面。
而DexClassLoader则不会存在/data/dalvik-cache文件夹里面,而是你指定的一个地方保存。
区别就产生在这里:/data/dalvik-cache是系统默认的classes.dex保存位置,而且普通用户没有读写权限,因此如果一个未安装的apk文件使用PathClassLoader来加载的话,没有权限把加载过后的类写到/data/dalvik-cache中去,因此当系统去这个文件夹寻找的时候,就找不到这个类了。而对于已经安装过的apk文件,在/data/dalvik-cache文件夹中有对应的classes.dex文件,所以PathClassLoader可以读写。我试过,如果在已经root的手机上改变/data/dalvik-cache的权限:
adb shell
su chmod 777 /data/dalvik-cache
那么这个时候,PathClassLoader也可以用来加载未安装的apk文件。但是普通用户不可能去改变这个权限的,因此,对于未安装的apk只能用DexClassLoader来安装。