国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 學(xué)院 > 開(kāi)發(fā)設(shè)計(jì) > 正文

APT技術(shù)

2019-11-09 17:49:54
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

官方文檔:Getting Started with the Annotation PRocessing Tool (apt)

Annotation

如果想學(xué)習(xí)APT,那么就必須先了解Annotation的基礎(chǔ),這里附加我另外一篇文章的地址: Annotation - QQ_20198405的博客 - 博客頻道 - CSDN.NET

APT

APT(Annotation Processing Tool)是一種處理注解的工具,它對(duì)源代碼文件進(jìn)行檢測(cè)找出其中的Annotation,使用Annotation進(jìn)行額外的處理。 Annotation處理器在處理Annotation時(shí)可以根據(jù)源文件中的Annotation生成額外的源文件和其它的文件(文件具體內(nèi)容由Annotation處理器的編寫(xiě)者決定),APT還會(huì)編譯生成的源文件和原來(lái)的源文件,將它們一起生成class文件。

創(chuàng)建Annotation Module

新建一個(gè)名稱(chēng)為annotation的java Library,主要放置一些項(xiàng)目中需要使用到的Annotation和關(guān)聯(lián)代碼。 這里簡(jiǎn)單自定義了一個(gè)注解:

@Target(ElementType.TYPE)@Retention(RetentionPolicy.CLASS)public @interface AptAnnotation {}

配置build.gradle

apply plugin: 'java'dependencies { compile fileTree(dir: 'libs', include: ['*.jar'])}sourceCompatibility = "1.7"targetCompatibility = "1.7"

創(chuàng)建Compiler Module

新建一個(gè)名為compiler的Java Library,這個(gè)類(lèi)將會(huì)寫(xiě)代碼生成的相關(guān)代碼。核心就是在這里。

配置build.gradle

apply plugin: 'java'tasks.withType(JavaCompile) { options.encoding = "UTF-8"}dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) compile 'com.google.auto.service:auto-service:1.0-rc2' compile 'com.squareup:javapoet:1.7.0' compile project(':annotation')}sourceCompatibility = "1.7"targetCompatibility = "1.7"AutoService 主要的作用是注解 processor 類(lèi),并對(duì)其生成 META-INF 的配置信息。JavaPoet 這個(gè)庫(kù)的主要作用就是幫助我們通過(guò)類(lèi)調(diào)用的形式來(lái)生成代碼。tasks.withType是設(shè)置編碼格式,避免AptProcesser 中的中文注釋報(bào)錯(cuò)依賴上面創(chuàng)建的annotation Module。

定義Processor類(lèi)

生成代碼相關(guān)的邏輯就放在這里。

@AutoService(Processor.class) public class AptProcesser extends AbstractProcessor { @Override public Set<String> getSupportedAnnotationTypes() { return Collections.singleton(AptAnnotation.class.getCanonicalName()); } @Override public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { return false; } }

生成第一個(gè)類(lèi)

我們接下來(lái)要生成下面這個(gè)HelloWorld的代碼:

package com.example.helloworld; public final class HelloWorld { public static void main(String[] args) { System.out.println("Hello, JavaPoet!"); } }

修改上述AptProcesser 的process方法

@Override public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) { MethodSpec main = MethodSpec.methodBuilder("main") .addModifiers(Modifier.PUBLIC, Modifier.STATIC) .returns(void.class) .addParameter(String[].class, "args") .addStatement("$T.out.println($S)", System.class, "Hello, JavaPoet!") .build(); TypeSpec helloWorld = TypeSpec.classBuilder("HelloWorld") .addModifiers(Modifier.PUBLIC, Modifier.FINAL) .addMethod(main) .build(); JavaFile javaFile = JavaFile.builder("com.example.helloworld", helloWorld) .build(); try { javaFile.writeTo(processingEnv.getFiler()); } catch (IOException e) { e.printStackTrace(); } return false; }

在app中使用

配置項(xiàng)目根目錄的build.gradle

dependencies { classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'}

配置app的build.gradle

apply plugin: 'com.android.application'apply plugin: 'com.neenbedankt.android-apt'//...dependencies { //.. compile project(':annotation') apt project(':compiler')}

編譯使用

@AptAnnotationpublic class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); }}

點(diǎn)擊Android Studio的ReBuild Project,可以在在app的 build/generated/source/apt/debug 目錄下,即可看到生成的代碼。

基于注解的View注入:DIActivity

到目前我們還沒(méi)有使用注解,上面的@AptAnnotation 也沒(méi)有實(shí)際用上,下面我們做一些更加實(shí)際的代碼生成。實(shí)現(xiàn)基于注解的View,代替項(xiàng)目中的findByView 。這里僅僅是學(xué)習(xí)怎么用APT,如果真的想用DI框架,推薦使用ButterKnife,功能全面。

第一步,在annotation module創(chuàng)建@DIActivity、@DIView注解。

@Target(ElementType.TYPE)@Retention(RetentionPolicy.CLASS)public @interface DIActivity {}@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)public @interface DIView { int value() default 0;}

第二步,創(chuàng)建Diprocessor方法

@AutoService(Processor.class)public class DIProcessor extends AbstractProcessor { private Elements elementUtils; @Override public Set<String> getSupportedAnnotationTypes() { // 規(guī)定需要處理的注解 return Collections.singleton(DIActivity.class.getCanonicalName()); } @Override public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { System.out.println("DIProcessor"); Set<? extends Element> elements = roundEnv.getElementsAnnotatedWith(DIActivity.class); for (Element element : elements) { // 判斷是否Class TypeElement typeElement = (TypeElement) element; List<? extends Element> members = elementUtils.getAllMembers(typeElement); MethodSpec.Builder bindViewMethodSpecBuilder = MethodSpec.methodBuilder("bindView") .addModifiers(Modifier.PUBLIC, Modifier.STATIC) .returns(TypeName.VOID) .addParameter(ClassName.get(typeElement.asType()), "activity"); for (Element item : members) { DIView diView = item.getAnnotation(DIView.class); if (diView == null){ continue; } bindViewMethodSpecBuilder.addStatement(String.format("activity.%s = (%s) activity.findViewById(%s)",item.getSimpleName(),ClassName.get(item.asType()).toString(),diView.value())); } TypeSpec typeSpec = TypeSpec.classBuilder("DI" + element.getSimpleName()) .addModifiers(Modifier.PUBLIC, Modifier.FINAL) .addMethod(bindViewMethodSpecBuilder.build()) .build(); JavaFile javaFile = JavaFile.builder(getPackageName(typeElement), typeSpec).build(); try { javaFile.writeTo(processingEnv.getFiler()); } catch (IOException e) { e.printStackTrace(); } } return true; } private String getPackageName(TypeElement type) { return elementUtils.getPackageOf(type).getQualifiedName().toString(); } @Override public synchronized void init(ProcessingEnvironment processingEnv) { super.init(processingEnv); elementUtils = processingEnv.getElementUtils(); } @Override public SourceVersion getSupportedSourceVersion() { return SourceVersion.RELEASE_7; }}

第三步,使用DIActivity

@AptAnnotation@DIActivitypublic class MainActivity extends AppCompatActivity { @DIView(R.id.text1) TextView textView1; @DIView(R.id.text2) TextView textView2; @DIView(R.id.text3) TextView textView3; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); DIMainActivity.bindView(this); textView1.setText("text1"); textView2.setText("text2"); textView3.setText("text3"); }}

實(shí)際上就是通過(guò)apt生成以下代碼:

public final class DIMainActivity { public static void bindView(MainActivity activity) { activity.textView1 = (android.widget.TextView) activity.findViewById(2131427413); activity.textView2 = (android.widget.TextView) activity.findViewById(2131427414); activity.textView3 = (android.widget.TextView) activity.findViewById(2131427415); }}

常用方法

常用Element子類(lèi)

TypeElement:類(lèi)ExecutableElement:成員方法

VariableElement:成員變量

通過(guò)包名和類(lèi)名獲取TypeName

TypeName targetClassName = ClassName.get("PackageName", "ClassName");通過(guò)Element獲取TypeNameTypeName type = TypeName.get(element.asType());獲取TypeElement的包名String packageName = processingEnv.getElementUtils().getPackageOf(type).getQualifiedName().toString();獲取TypeElement的所有成員變量和成員方法List<? extends Element> members = processingEnv.getElementUtils().getAllMembers(typeElement);

總結(jié):

推薦閱讀dagger2、dbflow、ButterKnife等基于apt的開(kāi)源項(xiàng)目代碼。JavaPoet 也有很多例子可以學(xué)習(xí)。

源碼傳送 參考: Android APT(編譯時(shí)代碼生成)最佳實(shí)踐 - 推酷 例子: 代碼傳送(稍加注釋?zhuān)?Android 利用 APT 技術(shù)在編譯期生成代碼 - hb707934728的博客 - 博客頻道 - CSDN.NET

相關(guān)文章: android-apt 翻譯 - 簡(jiǎn)書(shū) 原文hvisser / android-apt — Bitbucket Annotation-Processing-Tool詳解 | qiushao http://qiushao.net/2015/07/07/Annotation-Processing-Tool%E8%AF%A6%E8%A7%A3/ AndroidSutdio 編譯時(shí)自動(dòng)生成源代碼 | Septenary http://www.septenary.cn/2015/12/19/AndroidSutdio-%E7%BC%96%E8%AF%91%E6%97%B6%E8%87%AA%E5%8A%A8%E7%94%9F%E6%88%90%E6%BA%90%E4%BB%A3%E7%A0%81/


Android 打造編譯時(shí)注解解析框架 這只是一個(gè)開(kāi)始 - Hongyang - 博客頻道 - CSDN.NET http://blog.csdn.net/lmj623565791/article/details/43452969 Android 如何編寫(xiě)基于編譯時(shí)注解的項(xiàng)目 - Hongyang - 博客頻道 - CSDN.NET http://blog.csdn.net/lmj623565791/article/details/51931859

bug解決: Android Studio出現(xiàn)Error:No service of type Factor… - 簡(jiǎn)書(shū) http://www.jianshu.com/p/c4f4894ad215 Android Studio Error—Gradle: 錯(cuò)誤:編碼 GBK 的不可映射字符的 - 黑暗領(lǐng)域 - 博客頻道 - CSDN.NET http://blog.csdn.net/sljjyy/article/details/11976099


發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 金湖县| 方正县| 黔东| 收藏| 平塘县| 张家界市| 利辛县| 东明县| 石棉县| 镇远县| 博野县| 松原市| 北川| 五家渠市| 泾源县| 封丘县| 蕲春县| 德清县| 余干县| 务川| 仪陇县| 洮南市| 花垣县| 久治县| 嘉祥县| 木兰县| 会昌县| 德江县| 河北区| 甘洛县| 临西县| 顺义区| 涞源县| 苗栗县| 蒲城县| 乐业县| 湟中县| 诸城市| 万州区| 手游| 大庆市|