我有一个类,在其中进行一些运行时注释扫描,但它使用已弃用的 DexFile API,这会导致 LogCat 中出现警告:
W/zygote64: Opening an oat file without a class loader. Are you using the deprecated DexFile APIs?
。 我想删除此消息并使用正确的 API。文档建议
PathClassLoader
,但我不明白它在功能上与 DexFile
有何等价。我可以将 PathClassLoader
与 DexFile
实例结合使用,虽然它确实有效,但它给了我更多警告,并且扫描时间更长。为了清楚起见,我在下面写了注释扫描器。如果有人可以建议如何删除这些警告消息以及DexFile
的替代方案,这样我在删除它后就不会遇到功能损坏的问题,我将非常感激。
class AnnotationScanner {
companion object {
fun classesWithAnnotation(
context: Context,
annotationClass: Class<out Annotation>,
packageName: String? = null
): Set<Class<*>> {
return Pair(context.packageCodePath, context.classLoader)
.letAllNotNull { packageCodePath, classLoader ->
Pair(DexFile(packageCodePath), classLoader)
}
?.letAllNotNull { dexFile, classLoader ->
dexFile
.entries()
?.toList()
?.filter { entry ->
filterByPackageName(packageName, entry)
}
?.map {
dexFile.loadClass(it, classLoader)
}
?.filter { aClass ->
filterByAnnotation(aClass, annotationClass)
}
?.toSet()
} ?: emptySet<Class<*>>().wlog { "No ${annotationClass.simpleName} annotated classes found" }
}
private fun filterByAnnotation(aClass: Class<*>?, annotationClass: Class<out Annotation>): Boolean {
return aClass
?.isAnnotationPresent(annotationClass)
?.also {
it.ifTrue {
Timber.w("Found ${annotationClass.simpleName} on $aClass")
}
}
?: false
}
private fun filterByPackageName(packageName: String?, entry: String) =
packageName?.let { entry.toLowerCase().startsWith(it.toLowerCase()) } ?: true
}
}
您可以说没有任何东西可以替代您的案例的 DexFile,但还有另一种方法可以使用
Annotation Processor
扫描文件,您可以搜索以查找有关它的文档
我会给你一个如何获取类名称的例子
您可以在构建时扫描并在 java 类上编写类名称列表,然后使用生成的类来获取类名称,而不是在运行时扫描类
@SupportedAnnotationTypes("*")
public class Processor extends AbstractProcessor {
private ProcessingEnvironment mProcessingEnvironment;
@Override
public synchronized void init(ProcessingEnvironment processingEnvironment) {
super.init(processingEnvironment);
mProcessingEnvironment = processingEnvironment;
}
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
Types typeUtils = mProcessingEnvironment.getTypeUtils();
List<String> modelsClassesNames = new ArrayList<>();
TypeElement oModelTypeElement = processingEnv.getElementUtils().getTypeElement("com.insidjam.core.orm.OModel"); // Replace com.example.OModel with the package and name of your OModel class
mProcessingEnvironment.getMessager().printMessage(Diagnostic.Kind.NOTE, "Generating models names");
for (TypeElement annotation : annotations) {
for(Element element : roundEnv.getRootElements()){
if (element.getKind().isClass()) {
TypeMirror oModelType = oModelTypeElement.asType();
TypeMirror elementType = element.asType();
if (typeUtils.isSubtype(elementType, oModelType)) {
String className = ((TypeElement) element).getQualifiedName().toString();
modelsClassesNames.add(className);
System.out.println("Processing model: " + className);
}
}
}
}
generateClass(modelsClassesNames);
return true;
}
private void generateClass(List<String> classesNames) {
try {
String baseClassName = "ModelRegistry";
String relativeClassName = "com.example.annotationprocessor."+baseClassName;
JavaFileObject jfo = mProcessingEnvironment.getFiler().createSourceFile(relativeClassName);
try (Writer writer = jfo.openWriter()) {
writer.write("package com.example.annotationprocessor;\n\n");
writer.write("public class " + baseClassName + " {\n\n");
writer.write(" public static String[] getClassesNames() {\n");
writer.write(" return new String[] {\n");
for(int i = 0; i < classesNames.size(); i++){
String className = classesNames.get(i);
writer.write(" \"");
writer.write(className);
if(i < classesNames.size() -1) {
writer.write("\",");
}else{
writer.write("\"");
}
}
writer.write(" };\n");
writer.write(" }\n");
writer.write("}\n");
}
} catch (Exception e) {
mProcessingEnvironment.getMessager().printMessage(Diagnostic.Kind.NOTE, "Unable to write ******" + e.getMessage());
e.printStackTrace();
}
}
}
然后使用生成的类,如下所示
import com.example.annotationprocessor.ModelRegistry;
ModelRegistry.getClassesNames()