我正在尝试为我正在开发的安卓框架实现一个包扫描功能,类似于Spring的component-scan。基本上,我希望能够指定一个基本包,例如com.foo.bar,并检索所有具有特定注释的Class实例。我不想把每个组件都注册到我的框架中,因为这会破坏自动扫描的目的。
根据我的研究,Java似乎不可能使用反射检索给定包名的资源。然而,我简要地看了一下反射框架,我想知道是否有一个与Android兼容的版本。如果没有,也许有一种稍微不那么明显的方式来完成我想做的事情。
我稍微看了一下Spring源代码,看看他们是如何做到这一点的,但我不认为他们正在做的事情在Dalvik运行时中会起作用。
更新
目前,下面的代码是检索所有包含特定注释的类的最好方法,但坦率地说,这是一个非常糟糕的解决方案。它对ClassLoader做了一些非常不安全的假设,加上它扫描(并加载)所有应用程序类。
public Set<Class<?>> getClassesWithAnnotation(Class<? extends Annotation> annotation) {
Set<Class<?>> classes = new HashSet<Class<?>>();
Field dexField = PathClassLoader.class.getDeclaredField("mDexs");
dexField.setAccessible(true);
PathClassLoader classLoader = (PathClassLoader) Thread.currentThread().getContextClassLoader();
DexFile[] dexs = (DexFile[]) dexField.get(classLoader);
for (DexFile dex : dexs) {
Enumeration<String> entries = dex.entries();
while (entries.hasMoreElements()) {
String entry = entries.nextElement();
Class<?> entryClass = dex.loadClass(entry, classLoader);
if (entryClass != null && entryClass.isAnnotationPresent(annotation)) {
classes.add(entryClass);
}
}
}
return classes;
}发布于 2012-07-13 06:42:13
我同意乔普·埃根的观点,认为他的做法很好。在Android系统中,我尽量避免使用通常的web应用程序功能,这会导致一个持久的应用程序启动。我不使用反射或包扫描。
但如果你想..。如果我正确地理解了它,那么您希望有一个类的注释。与使用注释不同,您还可以使用标记接口(只需要更多的可能性)。
1)看
2) AndroidAnnotations
我更喜欢AndroidAnnotations的工作方式(也许AndroidAnnotations中的集成是更好的方法):它会自动添加一个额外的编译步骤来生成源代码,使用标准的AndroidAnnotations处理工具。因此,您可以根据编译期间生成的注释执行代码,而不是运行时扫描。
我认为Bean/EBean注释可以适用于您(只有一个类):https://github.com/excilys/androidannotations/wiki/Enhance%20custom%20classes
扫描功能不可用,请参阅此线程。
3)编写自己的注释处理器
发布于 2012-11-01 10:17:57
我想在运行时找到所有的子类。所以我一直在找android类扫描。这是我在网上收集到的最后一段代码。你会明白的。
public static void findSubClasses(Context context, Class parent) {
ApplicationInfo ai = context.getApplicationInfo();
String classPath = ai.sourceDir;
DexFile dex = null;
try {
dex = new DexFile(classPath);
Enumeration<String> apkClassNames = dex.entries();
while (apkClassNames.hasMoreElements()) {
String className = apkClassNames.nextElement();
try {
Class c = context.getClassLoader().loadClass(className);
if (parent.isAssignableFrom(c)) {
android.util.Log.i("nora", className);
}
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// android.util.Log.i("nora", className);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
try {
dex.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}发布于 2012-07-10 20:18:14
编辑:
我在安卓问题追踪器中找到了本期。ClassLoader.getResource(String)似乎“按预期工作”,因为它返回null。这是预期的,因为DalvikVM编译后不会保留资源。问题中列出了一些解决办法,但可能还有另一种方式来访问您想要的类。
使用PackageManager获取ApplicationInfo实例。ApplicationInfo有一个名为sourceDir的公共字段,它是指向该应用程序源目录位置的完整路径( String)。从这个File创建一个String,您应该能够导航到源目录中的包。一旦到了那里,您就可以使用我原来的答案中的方法来查找您要寻找的类。
String applicationSourceDir =
getPackageManager().getApplicationInfo(androidPackageName, 0).sourceDir;/EDIT
您应该能够使用ClassLoader.getResource(String)获得特定包的URL (传入的String是您感兴趣的由路径分隔符而不是句点分隔的包名)。使用这个URL,您可以调用getFile(),从它可以为包文件夹创建一个File。从那里调用packageFile.listFiles(),您就有了类/子包。
使用子包进行递归,并使用类使用静态Class方法查找Class.forName(String)对象。
https://stackoverflow.com/questions/11421085
复制相似问题