【问题标题】:how to cast a loaded class into an interface class in Android如何将加载的类转换为Android中的接口类
【发布时间】:2015-05-23 23:14:10
【问题描述】:

我有两个项目,比如说 projectMain 和 projectPlugin。 我有一个接口类。

这是接口类代码:

package com.far.lib;

public interface IPlugin {

    public String getNamaModul();
    public String getNamaPaket();
}

我使用 projectMain 作为 projectPlugin 的库项目。 我创建了一个从projectMain实现接口类的类,代码如下:

package com.example.helloworld.plugin;

public class PluginHelloWorld implements com.far.lib.IPlugin{

    @Override
    public String getNamaModul() {
        // TODO Auto-generated method stub
        return "Modul Hello World";
    }

    @Override
    public String getNamaPaket() {
        // TODO Auto-generated method stub
        return "com.example.helloworld";
    }

}

然后我编译 projectPlugin 得到一个 apk 文件,我将 apk 文件更改为一个 jar 文件,并在其中添加一个清单文件,这是清单代码:

Manifest-Version: 1.0
Module-Class: com.example.helloworld.plugin.PluginHelloWorld <-- this line of code is the code that i added in the manifest file

然后我有一个从 jar 文件中读取来加载 jar 文件的类。这是代码:

public class PluginManager {

public static List<PluginModel> getPlugins(Activity activty) {
    List<PluginModel> plugins = new ArrayList<PluginModel>();
    File pluginLoc = new File(Environment.getExternalStorageDirectory()
            + "/Plugin/");

    File[] pluginList = pluginLoc.listFiles(new FileFilter() {
        @Override
        public boolean accept(File pathname) {
            Log.d("file path", pathname.toString());
            return pathname.getPath().toLowerCase().endsWith(".jar");
        }
    });
    // URL[] urls = new URL[pluginList.length];
        for (int i = 0; i < pluginList.length; i++) {
            JarFile jarFile = null;
            try {
                jarFile = new JarFile(pluginList[i]);
                Manifest manifest = jarFile.getManifest();
                String ModuleClassName = manifest.getMainAttributes().getValue(
                        "Module-Class");
                Log.d("test", ModuleClassName);
                File DexOutputFile = activty.getDir("outdex",
                        Context.MODE_PRIVATE);
                DexClassLoader dcl = new DexClassLoader(
                        pluginList[i].getAbsolutePath(),
                        DexOutputFile.getAbsolutePath(), null,
                        ClassLoader.getSystemClassLoader());
                Class<?> clazz = dcl.loadClass(ModuleClassName);
                // Log.d("test", clazz.getClassLoader().toString());
                // Log.d("test1",IPlugin.class.getClassLoader().toString());
                IPlugin temp = (IPlugin) clazz.newInstance();
                plugins.add(new PluginModel(namaModul, namaPaket));
            } catch (Exception e) {
               e.printStackTrace();
           }
       }
       return plugins;
    }
}

我得到如下图所示的 ClassCastException 错误:

03-20 20:53:30.453: W/System.err(15986): java.lang.ClassCastException: com.example.helloworld.plugin.PluginHelloWorld 不能转换为 com.far.lib.IPlugin 03-20 20:53:30.453: W/System.err(15986): 在 com.far.plugin.PluginManager.getPlugins(PluginManager.java:61) 03-20 20:53:30.453: W/System.err(15986): 在 com.far.exampleplugin2.MainActivity.onResume(MainActivity.java:32) 03-20 20:53:30.453: W/System.err(15986): 在 android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1192) 03-20 20:53:30.453: W/System.err(15986): 在 android.app.Activity.performResume(Activity.java:5211) 03-20 20:53:30.453: W/System.err(15986): 在 android.app.ActivityThread.performResumeActivity(ActivityThread.java:2780) 03-20 20:53:30.453: W/System.err(15986): 在 android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2819) 03-20 20:53:30.453: W/System.err(15986): 在 android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2266) 03-20 20:53:30.453: W/System.err(15986): 在 android.app.ActivityThread.access$600(ActivityThread.java:141) 03-20 20:53:30.453: W/System.err(15986): 在 android.app.ActivityThread$H.handleMessage(ActivityThread.java:1256) 03-20 20:53:30.453: W/System.err(15986): 在 android.os.Handler.dispatchMessage(Handler.java:99) 03-20 20:53:30.453: W/System.err(15986): 在 android.os.Looper.loop(Looper.java:137) 03-20 20:53:30.453: W/System.err(15986): 在 android.app.ActivityThread.main(ActivityThread.java:5103) 03-20 20:53:30.453: W/System.err(15986): 在 java.lang.reflect.Method.invokeNative(Native Method) 03-20 20:53:30.453: W/System.err(15986): 在 java.lang.reflect.Method.invoke(Method.java:525) 03-20 20:53:30.453: W/System.err(15986): 在 com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:737) 03-20 20:53:30.453: W/System.err(15986): 在 com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553) 03-20 20:53:30.453: W/System.err(15986): at dalvik.system.NativeStart.main(Native Method)

我用Log打印了clazz和IPlugin的每个classloader,结果不一样。这是结果:

03-20 20:56:09.253: D/test(16698): dalvik.system.DexClassLoader[DexPathList[[zip file "/storage/emulated/0/Plugin/HelloWorld1.jar"],nativeLibraryDirectories=[/系统/库]]] 03-20 20:56:09.253: D/test1(16698): dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/com.far.exampleplugin2-1.apk"],nativeLibraryDirectories=[/data /app-lib/com.far.exampleplugin2-1, /system/lib]]]

我在这里要问的是如何将加载的类从 projectMain 转换为接口类?

谢谢。

【问题讨论】:

    标签: java android plugins interface casting


    【解决方案1】:

    如果类加载不兼容,Java 中的兼容类会发生 ClassCastException。如果系统类加载器未加载您的应用程序,则可能会发生这种情况。由于我不是 android 专家,我不确定锁定的类加载器是否是系统类加载器。因此,您可以使用当前执行的类的类加载器 this.getClass().getClassLoader() 或您希望与 IPlugin.class.getClassLoader() 兼容的接口之一作为父类加载器来配置 DexClassLoader。这些是您需要兼容的类加载器。 Thread.currentThread().getContextClassLoader() 也值得一试。

                DexClassLoader dcl = new DexClassLoader(
                        pluginList[i].getAbsolutePath(),
                        DexOutputFile.getAbsolutePath(), null,
                        IPlugin.class.getClassLoader());
    

    【讨论】:

    • 我在使用您的答案时发现了新的警告和错误。警告:03-21 09:58:11.524: W/dalvikvm(2326): Class resolved by unexpected DEX: Lcom/example/helloworld/plugin/PluginHelloWorld;(0xa5465b30):0x97ee3000 ref [Lcom/far/lib/IPlugin;] Lcom/far/lib/IPlugin;(0xa543e0a8):0x98015000 03-21 09:58:11.524: W/dalvikvm(2326): (Lcom/example/helloworld/plugin/PluginHelloWorld; had used a different Lcom/far/lib/IPlugin; during pre-verification) 错误:03-21 09:52:57.308: E/AndroidRuntime(2147): java.lang.IllegalAccessError: Class ref in pre-verified class resolved to unexpected implementation
    猜你喜欢
    • 2011-07-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多