我正在创建一个允许插件视图的家庭自动化应用程序。
我有以下代码作为概念证明:
我创建了一个带有插件接口的android库项目:
package com.strutton.android.UIPlugInLib;
import android.app.Dialog;
public interface IRDroidInterface {
public Dialog buildConfigDialog(int ID);
// Other method signatures here
}
我已经能够在一个单独的项目中创建一个类作为示例插件(并将其导出到apk),我将其推送到我的应用程序的文件目录:
package com.strutton.android.testloadclass;
import com.strutton.android.UIPlugInLib.IRDroidInterface;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.view.View;
import android.widget.Button;
public class MyTestClass_IRDroidUIPlugIn extends Button implements IRDroidInterface{
public final Activity mActivity;
public MyTestClass_IRDroidUIPlugIn(Activity activity) {
super((Context)activity);
mActivity = activity;
setText("I was loaded dynamically! (1)");
setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
setText("I was Clicked dynamically! (" + getId() +")");
}}
);
}
public Dialog buildConfigDialog(int ID){
AlertDialog.Builder builder = new AlertDialog.Builder((Context)mActivity);
builder.setMessage("Click the Button...(1)")
.setCancelable(false)
.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
mActivity.dialogDismiss();
}
});
return builder.create();
}
}
我可以在运行时加载这个类,并使用以下代码创建它的实例(在我的onCreate()
中):
package com.strutton.android.testplugin;
try {
final File filesDir = this.getFilesDir();
final File tmpDir = getDir("dex", 0);
final DexClassLoader classloader = new DexClassLoader( filesDir.getAbsolutePath()+"/testloadclass.apk",
tmpDir.getAbsolutePath(),
null, this.getClass().getClassLoader());
final Class<View> classToLoad =
(Class<View>) classloader.loadClass("com.strutton.android.testloadclass.MyTestClass_IRDroidUIPlugIn");
mybutton = (View) classToLoad.getDeclaredConstructor(Context.class).newInstance(this);
mybutton.setId(2);
main.addView((View)mybutton);
} catch (Exception e) {
e.printStackTrace();
}
setContentView(main);
}
protected Dialog onCreateDialog(int id) {
switch (id) {
case 1:
// this is the offending line 57
return ((IRDroidInterface) mybutton).buildConfigDialog(id);
}
return null;
}
我希望插件能够显示插件中定义的配置对话框。当我致电buildConfigDialog(id)
时,我会收到以下ClassCastException
:
04-20 20:49:45.865: W/System.err(354): java.lang.ClassCastException: com.strutton.android.testloadclass.MyTestClass_IRDroidUIPlugIn
04-20 20:49:45.894: W/System.err(354): at com.strutton.android.testplugin.TestpluginActivity.onCreate(TestpluginActivity.java:57)
我在这里缺少什么?我现在谷歌搜索了一天半,但找不到解决方案。
提前致谢。
答案 0 :(得分:3)
我怀疑问题是你的应用程序和你加载的dex文件中都存在IRDroidInterface接口。当您动态加载MyTestClass_IRDroidUIPlugIn类时,由于它来自dex文件,它实现了dex文件中的接口类,而不是应用程序中的接口类。
如果你可以确保接口类没有包含在插件的dex文件中,我相信你所拥有的应该可以正常工作。
不幸的是,如果您使用eclipse或ant构建插件apk,这可能会很棘手。一个(相当丑陋)的解决方案是在构建之后从dex文件中删除接口类。即,用baksmali反汇编它,删除接口的.smali文件,然后用smali重新组装。
答案 1 :(得分:0)
您可以使用DexClassLoader的自定义实现来解决此问题。 覆盖findclass并仅返回应用中不是库的接口。
package re.execute;
import dalvik.system.DexClassLoader;
public class DexLoader extends DexClassLoader{
public DexLoader(String dexPath, String optimizedDirectory, String libraryPath, ClassLoader parent) {
super(dexPath, optimizedDirectory, libraryPath, parent);
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
if("re.execute.ILoader".equals(name)){
return ILoader.class;
}
return super.findClass(name);
}
}