DexClassLoader使用-(1)

可以先参考java的java类加载器

一、DexClassLoader

  一般情况下,我们使用import就可以了,为什么还要使用类装载器呢?

import中所引用的类文件有两个特点:

1.一定在存在于本地,当程序运行时需要这个类时,内部类装载器就会自动装载,程序员感知不到这个过程。

2.编译时一定要在现场,否则会因找不到引用文件而不能正常编译。

  但是在有的情况下,要用的类不一定满足这些条件,如从运程下载一个类并在本地运行,例子如applet执行的java,另一种是要引用的class文件不方便在编译时直接参与 ,而只能在运行时动态调用。如在android中修改FrameWork中已经有的类,为了保持与原生的FrameWork最小化的修改,可以使用类装载器动态装载自己定义 的jar包。

 

二、DexClassLoader的使用方法

  有两个apk。

  • 插件部分

定义了类PluginClass。如下

public class PluginClass {
    public PluginClass(){
        Log.d("PluginCLass", "PluginClass initiazed");
    }

    public int function1(int a,int b){
        return a +b;
    }
}

还定义了

一个空的Activity,这个作用只是为了让宿主apk中可以找到package而已,所以只要有就可以了。

<activity
            android:name=".BlankActivity"
            android:label="@string/title_activity_blank" >
            <intent-filter>
                <action android:name="com.example.lsj.testapp.plugin.client"/>
            </intent-filter>
        </activity>

我们将可以通过intent-filter得到相关的信息。

  • 宿主部分

通过下面的ClassLoader可以装载插件中的类,再构造出Method对象 ,并构造出Method对象所使用的参数对象 ,然后才能调用 。

ublic void useDexClassLoader(){
        Intent intent = new Intent("com.example.lsj.testapp.plugin.client", null);
        PackageManager pm = getPackageManager();
        final List<ResolveInfo> plugins = pm.queryIntentActivities(intent, 0);
        ResolveInfo rinfo = plugins.get(0);
        ActivityInfo ainfo = rinfo.activityInfo;

        String div = System.getProperty("path.separator");
        String packageName = ainfo.packageName;
        String dexPath = ainfo.applicationInfo.sourceDir;
        String dexOutputDir = getApplicationInfo().dataDir;
        String libPath = ainfo.applicationInfo.nativeLibraryDir;

        DexClassLoader dexClassLoader = new DexClassLoader(dexPath,
                dexOutputDir,libPath,this.getClass().getClassLoader());
        try{
            Class <?> clazz = dexClassLoader.loadClass(packageName+".PluginClass");
            Object obj = clazz.newInstance() ;
            Class [] params = new Class[2];
            params[0]= Integer.TYPE;
            params[1] = Integer.TYPE ;
            Method action = clazz.getMethod("function1", params) ;
            Integer ret = (Integer)action.invoke(obj, 1,2);
            Log.e(TAG, "return value is :"+ ret);
            
        }catch ( ClassNotFoundException e){

        }catch (InstantiationException e2 ){

        }catch (IllegalAccessException e3){

        }catch (NoSuchMethodException e4){

        }catch (InvocationTargetException e5){

        }
    }

DexClassLoader方法参数:

dexPath:目标所在的apk或者jar文件的路径,装载器将从路径中寻找指定的目标类。

dexOutputDir:由于dex 文件在APK或者 jar文件中,所以在装载前面前先要从里面解压出dex文件,这个路径就是dex文件存放的路径,在 android系统中,一个应用程序对应一个linux用户id ,应用程序只对自己的数据目录有写的权限,所以我们存放在这个路径中。

libPath :目标类中使用的C/C++库。

最后一个参数是该装载器的父装载器,一般为当前执行类的装载器。

 这里我们得到的Class对象是CLassLoader可以识别的类,而PluginClass是程序执行后可以识别的类,此时仅仅装载了PluginClass的程序代码,还没有创建出其对象 ,接下来可以使用Class.newInsance()方法来调用PluginClass类的构造方法,并返回一个真正的PluginClass对象。

  但是我们不能直接去调用 PluginClass的任何方法,只能通过反射去调用其方法。

  反射机制时主要使用了Method类,Class对象的getMethod()方法可以返回这个类中任何方法,getMethod()有两个参数 ,一个是要访问的函数名,另一个是函数的参数类型。

  得到目标类的Method对象后,就可以调用Method对象的invoke方法,这个方法的第一个参数是执行目标函数的对象。

 

posted @ 2015-09-04 16:50  chuiyuan  阅读(1958)  评论(0编辑  收藏  举报