假设我的Android应用程序的源代码以这种方式打包:
src/
my/
app/
Module.java
ModuleManager.java
module/
ModuleA.java
ModuleB.java
其中Module
是:
public abstract class Module {
public abstract void run();
}
,ModuleA
和ModuleB
延伸Module
:
public class ModuleA extends Module {
@Override
public void run() { /* do something */ }
}
和ModuleManager
有一些辅助方法,其中一个用于检索所有Module
s:
public class ModuleManager {
private final static List<Module> modules;
static {
List<Module> tmp= new ArrayList<Module>();
tmp.add(new ModuleA());
tmp.add(new ModuleB());
modules= Collections.unmodifiableList(tmp);
}
public static List<Module> getModules(){
return modules;
}
}
如您所见,我手动填写了ModuleManager
中的模块列表。相反,我希望自动填充 module 包中所有Module
子类型的实例。
我尝试了几种基于反射的解决方案like this,其中涉及使用ClassLoader::getResource(String path)
检索模块包中的每个.class文件,但它总是返回空的枚举。我了解到这是由于Dalvik的VM和Java SE之间的区别,以及它在 classes.dex 中的.class文件的优化打包。然后,我尝试使用DexClassLoader
或PathClassLoader
从 / data / app / 导入应用程序的apk,并再次尝试不再尝试getResource()
方法。无论如何,我认为这不是正确的方向,可能这些东西在Java中已经是hackish /有缺陷,而且在Android中会更多。
你能建议我这样做吗?
非常感谢。
答案 0 :(得分:2)
在构建脚本中执行此操作的一种方法是,在编译之后但在调用dex来创建classes.dex之前,运行一个小脚本来获取modules文件夹中的类名并将其写入以说明要读取的application.properties文件from(或资源中的strings.xml)。
这样做的缺点是它不是你要求的纯java方法,它的优点是适用于2或10+个子类。希望这会有所帮助。
答案 1 :(得分:1)
如果您使用模块类添加XML或属性并从中动态创建它会怎样......它可能会是这样的
<modules>
<module>
my.app.module.ModuleA
</module>
<module>
my.app.module.ModuleB
</module>
</modules>
答案 2 :(得分:1)
另一个解决方案可能是利用类名称的命名约定,并使用Class.forName(className)
逐个检索所有这些约定。在我做的示例中,如果我知道所有模块按顺序命名为ModuleA
,ModuleB
,ModuleC
等等,我可以从ModuleA
开始检索所有模块并继续直到Class.forName("ModuleX")
失败。如果允许间隙但模块的数量有限(并且非常低),则可以对整个范围进行详尽的搜索。
当然,这可以在很少的情况下应用,并且以代表名称的可读性为代价。