如何使用 PathClassLoader 来替换已弃用的 DexFile API?

问题描述 投票:0回答:1

我有一个类,在其中进行一些运行时注释扫描,但它使用已弃用的 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
    }
}
android jvm classloader dalvik dex
1个回答
0
投票

您可以说没有任何东西可以替代您的案例的 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()

© www.soinside.com 2019 - 2024. All rights reserved.