在Android的App中动态的加载Java类

原文的地址:http://yenliangl.blogspot.com/2009/11/dynamic-loading-of-classes-in-your.html
我正在编写一个应用程序能够加载别人开发的应用插件。对于应用程序思路的实现,我首先想到的是使用 Class.forName 以及java.lang.reflective中的提供的方法。我比较倾向于使用 Class.forName(),像下面一样:

try {
         Class<?> handler = Class.forName(handlerClassName);
         Method m = handler.getDeclaredMethod(
                "addMyPreferences",
                Class.forName("android.content.Context"),
                Class.forName("android.preference.PreferenceCategory"),
                Class.forName("java.lang.String"));
         m.invoke(handler.newInstance(), this, mExtraSettingsCategory, defaultValue);
     } catch(ClassNotFoundException e) {
        // .....
     }
     // other exceptions that may be thrown by reflective API.

但是经过实践发现,上面的代码会出现ClassNotFoundException的异常。我怎么办?一个比较麻烦的问题在我的脑海里闪现,我猜想是不是别的开发者也会和我遇到同样的问题,于是我就谷歌查询,发现一个文档对我理解:为什么上面的代码会抛出ClassNotFoundException异常非常有帮助(点击这里)。
该文档上说,Java的基本动态加载模块依赖于java的parent-chaild层次结构和ClassLoader类。通过日志打印出类加载的顺序(层次)对于理解类的加载很有帮助。因此,我就这么做了。

ClassLoader cl = this.getClass().getClassLoader();
while (cl != null) {
    Log.d(TAG, "====> class loader: " + cl.getClass());
    cl = cl.getParent();
}


在我的电脑上,在类加载的时候打印显示加载了2个类分别是 dalvik.system.PathClassLoader类 和 java.lang.BootClassLoader类。最有趣的事情是使用 PathClassLoader类。查看它的文档发现 PathClassLoader类能够接受不同类型的值作为它的构造函数的参数,直接从文档上复制过来看:

public PathClassLoader  (String path, ClassLoader parent)

Creates a PathClassLoader that operates on a given list of files and directories. This method is equivalent to calling PathClassLoader(String, String, ClassLoader) with a null value for the second argument (see description there).

    * Directories containing classes or resources.
    * JAR/ZIP/APK files, possibly containing a "classes.dex" file.
    * "classes.dex" files.


好啦,基于文档上面的规定说明,我猜测使用apk文件名构造PathClassLoader 类实例,并且这个apk应用是在传递中创建,如下:

PathClassLoader("/data/app/org.startsmall.myapp.apk",
                ClassLoader.getSystemClassLoader());

因此,如果我想使用Class.forName()就应该从第三方应用开发者哪里知道要加载的类的名字,并且必须重新构造PathClassLoader 类实例从我的apk应用和第三方应用中加载类,下面是示例代码:

final String apkFiles =
            "/data/app/org.startsmall.myapp.apk:" + // myself
            // handlers defined by other developers
            "/data/app/" + handlerClassName.substring(0, lastDotPos) + ".apk";

        dalvik.system.PathClassLoader myClassLoader =
            new dalvik.system.PathClassLoader(
                apkFiles,
                ClassLoader.getSystemClassLoader());

         // ...

        try {
            Class<?> handler =
                Class.forName(handlerClassName, true, classLoader);

            // Call reflective APIs.

       } catch (ClassNotFoundException e) {
            // .....
       }

经过上面这些经验和错误,我的代码终于可以加载第三方的类和方法,并且可以执行达到预期的效果。


注:翻译的不好,请无视直接看原文。




原文地址:https://www.cnblogs.com/csnd/p/11800737.html