<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                [TOC] > APT(Annotation Processing Tool)是一種處理注釋的工具,它對源代碼文件進行檢測找出其中的Annotation,根據注解自動生成代碼。 Annotation處理器在處理Annotation時可以根據源文件中的Annotation生成額外的源文件和其它的文件(文件具體內容由Annotation處理器的編寫者決定),APT還會編譯生成的源文件和原來的源文件,將它們一起生成class文件。 ![](https://img.kancloud.cn/5c/1d/5c1d64f5d500aa0e0ccc1bdb222d43ee_600x362.png) ## annotationProcessor 與 android-apt **annotationProcessor** 是APT工具中的一種,他是google開發的內置框架,可以直接在build.gradle文件中使用,推薦大家使用 **android-apt** 是由一位開發者自己開發的apt框架,源代碼托管在[這里](https://bitbucket.org/hvisser/android-apt),目前不推薦大家使用了 ## 整體設計 一般基于APT實現一個框架,項目目錄一般分為三個部分 1. xxxx-annotation:該框架所使用的全部注解,及其相關類 2. xxxx-compiler:注解編譯處理器,引入“xxxx-annotation”,在編譯器把注解標注的相關目標類生成映射文件 3. xxxx-api/xxxx-library:功能的具體實現以及暴露給外面的api 下面我們仔細說是xxxx-compiler。 ## AbstractProcessor ~~~ @AutoService(Processor.class) public class MyProcessor extends AbstractProcessor { @Override public synchronized void init(ProcessingEnvironment env) { } @Override public boolean process(Set<? extends TypeElement> annoations, RoundEnvironment env) { } @Override public Set<String> getSupportedAnnotationTypes() { } @Override public SourceVersion getSupportedSourceVersion( ~~~ ### init init(ProcessingEnvironment env): 【核心】 每一個注解處理器類都必須有一個空的構造函數。然而,這里有一個特殊的init()方法,它會被注解處理工具調用,并輸入ProcessingEnviroment參數。 ProcessingEnviroment提供很多有用的工具類Elements,Types和Filer。后面我們將看到詳細的內容? * Filer是個接口,支持通過注解處理器創建新文件? * Elements 元素操作輔助工具類 ### process process(Set annotations, RoundEnvironment env):【核心】 這相當于每個處理器的主函數main()。你在這里寫你的掃描、評估和處理注解的代碼,以及生成Java文件。 輸入參數annotations 請求處理的注解類型集合 輸入參數RoundEnviroment,可以讓你查詢出包含特定注解的被注解元素,相當于“有關全局源碼的上下文環境”。后面我們將看到詳細的內容。 @return 如果返回 true,則這些注解已聲明并且不要求后續 Processor 處理它們;如果返回 false,則這些注解未聲明并且可能要求后續 Processor 處理它們 ### getSupportedAnnotationTypes 這里你必須指定,這個注解處理器是注冊給哪個注解的。注意,它的返回值是一個字符串的集合,包含本處理器想要處理的注解類型的合法全稱。 換句話說,你在這里定義你的注解處理器注冊到哪些注解上。 ### getSupportedSourceVersion 用來指定你使用的Java版本。通常這里返回SourceVersion.latestSupported()。 ### 例子 ~~~ @AutoService(Processor.class) public class BindViewProcessor extends AbstractProcessor { private Messager mMessager; private Elements mElementUtils; private Map<String, ClassCreatorProxy> mProxyMap = new HashMap<>(); @Override public synchronized void init(ProcessingEnvironment processingEnv) { super.init(processingEnv); mMessager = processingEnv.getMessager(); mElementUtils = processingEnv.getElementUtils(); } @Override public Set<String> getSupportedAnnotationTypes() { HashSet<String> supportTypes = new LinkedHashSet<>(); supportTypes.add(BindView.class.getCanonicalName()); return supportTypes; } @Override public SourceVersion getSupportedSourceVersion() { return SourceVersion.latestSupported(); } @Override public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) { mMessager.printMessage(Diagnostic.Kind.NOTE, "processing..."); mProxyMap.clear(); //得到所有的注解 Set<? extends Element> elements = roundEnvironment.getElementsAnnotatedWith(BindView.class); for (Element element : elements) { VariableElement variableElement = (VariableElement) element; TypeElement classElement = (TypeElement) variableElement.getEnclosingElement(); String fullClassName = classElement.getQualifiedName().toString(); ClassCreatorProxy proxy = mProxyMap.get(fullClassName); if (proxy == null) { proxy = new ClassCreatorProxy(mElementUtils, classElement); mProxyMap.put(fullClassName, proxy); } BindView bindAnnotation = variableElement.getAnnotation(BindView.class); int id = bindAnnotation.value(); proxy.putElement(id, variableElement); } //通過遍歷mProxyMap,創建java文件 for (String key : mProxyMap.keySet()) { ClassCreatorProxy proxyInfo = mProxyMap.get(key); try { mMessager.printMessage(Diagnostic.Kind.NOTE, " --> create " + proxyInfo.getProxyClassFullName()); JavaFileObject jfo = processingEnv.getFiler().createSourceFile(proxyInfo.getProxyClassFullName(), proxyInfo.getTypeElement()); Writer writer = jfo.openWriter(); writer.write(proxyInfo.generateJavaCode()); writer.flush(); writer.close(); } catch (IOException e) { mMessager.printMessage(Diagnostic.Kind.NOTE, " --> create " + proxyInfo.getProxyClassFullName() + "error"); } } mMessager.printMessage(Diagnostic.Kind.NOTE, "process finish ..."); return true; ~~~ 通過roundEnvironment.getElementsAnnotatedWith(BindView.class)得到所有注解elements,然后將elements的信息保存到mProxyMap中,最后通過mProxyMap創建對應的Java文件,其中mProxyMap是ClassCreatorProxy的Map集合。 ClassCreatorProxy是創建Java代碼的代理類,如下: ~~~ public class ClassCreatorProxy { private String mBindingClassName; private String mPackageName; private TypeElement mTypeElement; private Map<Integer, VariableElement> mVariableElementMap = new HashMap<>(); public ClassCreatorProxy(Elements elementUtils, TypeElement classElement) { this.mTypeElement = classElement; PackageElement packageElement = elementUtils.getPackageOf(mTypeElement); String packageName = packageElement.getQualifiedName().toString(); String className = mTypeElement.getSimpleName().toString(); this.mPackageName = packageName; this.mBindingClassName = className + "_ViewBinding"; } public void putElement(int id, VariableElement element) { mVariableElementMap.put(id, element); } /** * 創建Java代碼 * @return */ public String generateJavaCode() { StringBuilder builder = new StringBuilder(); builder.append("package ").append(mPackageName).append(";\n\n"); builder.append("import com.example.gavin.apt_library.*;\n"); builder.append('\n'); builder.append("public class ").append(mBindingClassName); builder.append(" {\n"); generateMethods(builder); builder.append('\n'); builder.append("}\n"); return builder.toString(); } /** * 加入Method * @param builder */ private void generateMethods(StringBuilder builder) { builder.append("public void bind(" + mTypeElement.getQualifiedName() + " host ) {\n"); for (int id : mVariableElementMap.keySet()) { VariableElement element = mVariableElementMap.get(id); String name = element.getSimpleName().toString(); String type = element.asType().toString(); builder.append("host." + name).append(" = "); builder.append("(" + type + ")(((android.app.Activity)host).findViewById( " + id + "));\n"); } builder.append(" }\n"); } public String getProxyClassFullName() { return mPackageName + "." + mBindingClassName; } public TypeElement getTypeElement() { return mTypeElement; ~~~ 效果生成 ~~~ public class MainActivity_ViewBinding { public void bind(com.example.gavin.apttest.MainActivity host) { host.mButton = (android.widget.Button) (((android.app.Activity) host).findViewById(2131165218)); host.mTextView = (android.widget.TextView) (((android.app.Activity) host).findViewById(2131165321)); } } ~~~ ## javapoet 上面在ClassCreatorProxy中,通過StringBuilder來生成對應的Java代碼。這種做法是比較麻煩的,還有一種更優雅的方式,那就是javapoet。 ~~~ public class ClassCreatorProxy { //省略部分代碼... /** * 創建Java代碼 * @return */ public TypeSpec generateJavaCode2() { TypeSpec bindingClass = TypeSpec.classBuilder(mBindingClassName) .addModifiers(Modifier.PUBLIC) .addMethod(generateMethods2()) .build(); return bindingClass; } /** * 加入Method */ private MethodSpec generateMethods2() { ClassName host = ClassName.bestGuess(mTypeElement.getQualifiedName().toString()); MethodSpec.Builder methodBuilder = MethodSpec.methodBuilder("bind") .addModifiers(Modifier.PUBLIC) .returns(void.class) .addParameter(host, "host"); for (int id : mVariableElementMap.keySet()) { VariableElement element = mVariableElementMap.get(id); String name = element.getSimpleName().toString(); String type = element.asType().toString(); methodBuilder.addCode("host." + name + " = " + "(" + type + ")(((android.app.Activity)host).findViewById( " + id + "));"); } return methodBuilder.build(); } public String getPackageName() { return mPackageName; ~~~ 最后在?BindViewProcessor中 ~~~ @Override public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) { //省略部分代碼... //通過javapoet生成 for (String key : mProxyMap.keySet()) { ClassCreatorProxy proxyInfo = mProxyMap.get(key); JavaFile javaFile = JavaFile.builder(proxyInfo.getPackageName(), proxyInfo.generateJavaCode2()).build(); try { // 生成文件 javaFile.writeTo(processingEnv.getFiler()); } catch (IOException e) { e.printStackTrace(); } } mMessager.printMessage(Diagnostic.Kind.NOTE, "process finish ..."); return true; } ~~~ ## 參考資料 [深入理解Java:注解(Annotation)–編譯時注解的處理](https://blog.csdn.net/fei20121106/article/details/73742537) [你必須知道的APT、annotationProcessor、android-apt、Provided、自定義注解](https://blog.csdn.net/xx326664162/article/details/68490059) [【Android】APT](https://www.jianshu.com/p/7af58e8e3e18) [javapoet](https://github.com/square/javapoet) [ANNOTATION PROCESSING](http://hannesdorfmann.com/annotation-processing/annotationprocessing101)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看