一、上篇文章提到自定义processor中用到AutoService

文章中我们用到了AutoService, 使用@AutoService(Processor.class),编译后

AutoService会自动在META-INF文件夹下生成Processor配置信息文件,该文件里就是实现该服务接口的具体实现类。而当外部程序装配这个模块的时候,
就能通过该jar包META-INF/services/里的配置文件找到具体的实现类名,并装载实例化,完成模块的注入。
基于这样一个约定就能很好的找到服务接口的实现类,而不需要再代码里制定,方便快捷。应用依赖如下:
compile 'com.google.auto.service:auto-service:1.0-rc2'

  

二、javapoet常用api

JavaPoet是square推出的开源java代码生成框架,提供Java Api生成.java源文件。这个框架功能非常有用,我们可以很方便的使用它根据注解、数据库模式、协议格式等来对应生成代码。通过这种自动化生成代码的方式,可以让我们用更加简洁优雅的方式要替代繁琐冗杂的重复工作。引用依赖:

compile 'com.squareup:javapoet:1.7.0'

 

该项目结构如下:

相关类介绍

JavaFile A Java file containing a single top level class 用于构造输出包含一个顶级类的Java文件
TypeSpec A generated class, interface, or enum declaration 生成类,接口,或者枚举
MethodSpec A generated constructor or method declaration 生成构造函数或方法
FieldSpec A generated field declaration 生成成员变量或字段
ParameterSpec A generated parameter declaration 用来创建参数
AnnotationSpec A generated annotation on a declaration 用来创建注解
 

在JavaPoet中,JavaFile是对.java文件的抽象,TypeSpec是类/接口/枚举的抽象,MethodSpec是方法/构造函数的抽象,FieldSpec是成员变量/字段的抽象。这几个类各司其职,但都有共同的特点,提供内部Builder供外部更多更好地进行一些参数的设置以便有层次的扩展性的构造对应的内容

常用api:

  • addStatement() 方法负责分号和换行
  • beginControlFlow() + endControlFlow() 需要一起使用,提供换行符和缩进。
  • addCode() 以字符串的形式添加内
  • returns 添加返回值类型
  • .constructorBuilder() 生成构造器函数
  • .addAnnotation 添加注解
  • addSuperinterface 给类添加实现的接口
  • superclass 给类添加继承的父类
  • ClassName.bestGuess(“类全名称”) 返回ClassName对象,这里的类全名称表示的类必须要存在,会自动导入相应的包
  • ClassName.get(“包名”,”类名”) 返回ClassName对象,不检查该类是否存在
  • TypeSpec.interfaceBuilder(“HelloWorld”)生成一个HelloWorld接口
  • MethodSpec.constructorBuilder() 构造器
  • addTypeVariable(TypeVariableName.get(“T”, typeClassName)) 
    会给生成的类加上泛型

占位符

  • $L代表的是字面量
  • $S for Strings
  • $N for Names(我们自己生成的方法名或者变量名等等)
  • $T for Types

三、javapoet的使用

package com.example.helloworld;

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

  

上面的代码我们可以调用javapoet的api方法去生成:

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(); javaFile.writeTo(System.out);//可以看出,addModifiers对方法的修饰约束,addParameter添加方法参数 ,addStatement方法体,returns返回值,最后写入java文件中

  

代码和控制流程
大多数JavaPoet的API使用普通的旧的不可变的Java对象。也有建设者,方法链和可变参数使API友好。JavaPoet为类和接口(TypeSpec),fields(FieldSpec),方法和构造函数(MethodSpec),参数(ParameterSpec)和注释(AnnotationSpec)提供模型。
MethodSpec main = MethodSpec.methodBuilder("main")
.addCode(""
+ "int total = 0;\n"
+ "for (int i = 0; i < 10; i++) {\n"
+ " total += i;\n"
+ "}\n")
.build();

  

则会生成下面的代码

void main() {
int total = 0;
for (int i = 0; i < 10; i++) {
total += i;
}
}

  

我们可以子自定义方法去调用

private MethodSpec computeRange(String name, int from, int to, String op) {
return MethodSpec.methodBuilder(name)
.returns(int.class)
.addStatement("int result = 0")
.beginControlFlow("for (int i = " + from + "; i < " + to + "; i++)")
.addStatement("result = result " + op + " i")
.endControlFlow()
.addStatement("return result")
.build();
}

  

调用上面的方法后computeRange("multiply10to20", 10, 20, "*") 生成下面的java代码

int multiply10to20() {
int result = 0;
for (int i = 10; i < 20; i++) {
result = result * i;
}
return result;
}

  

对于$T泛型 ,我们的Java程序员喜欢我们的类型:他们让我们的代码更容易理解。JavaPoet在船上。它具有丰富的内置支持类型,包括自动生成import 语句。只是$T用来引用类型:

package com.example.helloworld;

import java.util.Date;

public final class HelloWorld {
Date today() {
return new Date();
}
}

  

要生成上面代码 可以用下面的javapoet去实现

MethodSpec today = MethodSpec.methodBuilder("today")
.returns(Date.class)
.addStatement("return new $T()", Date.class)
.build(); TypeSpec helloWorld = TypeSpec.classBuilder("HelloWorld")
.addModifiers(Modifier.PUBLIC, Modifier.FINAL)
.addMethod(today)
.build(); JavaFile javaFile = JavaFile.builder("com.example.helloworld", helloWorld)
.build(); javaFile.writeTo(System.out);

  

JavaPoet支持import static。它通过明确收集类型成员名称来完成。见下面代码:

JavaFile.builder("com.example.helloworld", hello)
.addStaticImport(hoverboard, "createNimbus")
.addStaticImport(namedBoards, "*")
.addStaticImport(Collections.class, "*")
.build();

  

如果我们想生成构造Constructors,也很简单:

public class HelloWorld {
private final String greeting; public HelloWorld(String greeting) {
this.greeting = greeting;
}
}

  

要实现上面java代码,用javapoet去实现,如下:

MethodSpec flux = MethodSpec.constructorBuilder()
.addModifiers(Modifier.PUBLIC)
.addParameter(String.class, "greeting")
.addStatement("this.$N = $N", "greeting", "greeting")
.build(); TypeSpec helloWorld = TypeSpec.classBuilder("HelloWorld")
.addModifiers(Modifier.PUBLIC)
.addField(String.class, "greeting", Modifier.PRIVATE, Modifier.FINAL)
.addMethod(flux)
.build();

  

还可定义枚举类

TypeSpec helloWorld = TypeSpec.enumBuilder("Roshambo")
.addModifiers(Modifier.PUBLIC)
.addEnumConstant("ROCK")
.addEnumConstant("SCISSORS")
.addEnumConstant("PAPER")
.build(); public enum Roshambo {
ROCK, SCISSORS, PAPER
}

  

还有匿名内部类的实现

TypeSpec comparator = TypeSpec.anonymousClassBuilder("")
.addSuperinterface(ParameterizedTypeName.get(Comparator.class, String.class))
.addMethod(MethodSpec.methodBuilder("compare")
.addAnnotation(Override.class)
.addModifiers(Modifier.PUBLIC)
.addParameter(String.class, "a")
.addParameter(String.class, "b")
.returns(int.class)
.addStatement("return $N.length() - $N.length()", "a", "b")
.build())
.build(); TypeSpec helloWorld = TypeSpec.classBuilder("HelloWorld")
.addMethod(MethodSpec.methodBuilder("sortByLength")
.addParameter(ParameterizedTypeName.get(List.class, String.class), "strings")
.addStatement("$T.sort($N, $L)", Collections.class, "strings", comparator)
.build())
.build();
This generates a method that contains a class that contains a method: void sortByLength(List<String> strings) {
Collections.sort(strings, new Comparator<String>() {
@Override
public int compare(String a, String b) {
return a.length() - b.length();
}
});
}

  

也可创建注解:

MethodSpec toString = MethodSpec.methodBuilder("toString")
.addAnnotation(Override.class)
.returns(String.class)
.addModifiers(Modifier.PUBLIC)
.addStatement("return $S", "Hoverboard")
.build(); //结果如下:
@Override
public String toString() {
return "Hoverboard";
}

  

创建注释javadoc

MethodSpec dismiss = MethodSpec.methodBuilder("dismiss")
.addJavadoc("Hides {@code message} from the caller's history. Other\n"
+ "participants in the conversation will continue to see the\n"
+ "message in their own history unless they also delete it.\n")
.addJavadoc("\n")
.addJavadoc("<p>Use {@link #delete($T)} to delete the entire\n"
+ "conversation for all participants.\n", Conversation.class)
.addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
.addParameter(Message.class, "message")
.build(); /**
* Hides {@code message} from the caller's history. Other
* participants in the conversation will continue to see the
* message in their own history unless they also delete it.
*
* <p>Use {@link #delete(Conversation)} to delete the entire
* conversation for all participants.
*/
void dismiss(Message message);

  

用法很多,还可以用FieldSpec.builder创建属性变量,ParameterSpec创建方法参数

四、总结 问题

如果我们在自定义processor的时候找不到javax.annotation.processing.*包下的类,则创建java module 而非android module

Android关于AutoService、Javapoet讲解的更多相关文章

  1. android studio 目录结构讲解

    android studio 目录结构讲解 src 毫无疑问,src目录是放置我们所有 Java代码的地方,它在这里的含义和普通 Java 项目下的 src目录是完全一样的,展开之后你将看到我们刚才创 ...

  2. Android进阶(二十三)Android开发过程之实例讲解

    Android开发过程之实例讲解 前言 回过头来审视之前做过的Android项目,发觉自己重新开发时忽然间不知所措了,间隔了太长时间没有开发导致自己的Android技能知识急剧下降.温故而知新. 废话 ...

  3. Android指纹识别API讲解,让你有更好的用户体验

    我发现了一个比较怪的现象.在iPhone上使用十分普遍的指纹认证功能,在Android手机上却鲜有APP使用,我简单观察了一下,发现Android手机上基本上只有支付宝.微信和极少APP支持指纹认证功 ...

  4. Android添加权限大讲解

    对于新手来说,最烦恼的不是如何从网上下载到安卓项目,而是下载到的安卓项目不知道如何添加权限和要添加哪些权限. 现在就针对安卓的权限来讲解这些权限应该具体用在什么地方 首先在项目下找到 AndroidM ...

  5. Android开发 retrofit入门讲解

    前言 retrofit基于okhttp封装的网络请求框架,网络请求的工作本质上是 OkHttp 完成,而 retrofit 仅负责网络请求接口的封装.如果你不了解OKhttp建议你还是先了解它在来学习 ...

  6. android位运算简单讲解

    一.前言 在查看源码中,经常会看到很多这样的符号“&”.“|”.“-”,咋一看挺高大上:仔细一看,有点懵:再看看,其实就是大学学过的再普通不过的与.或.非.今天小盆友就以简单的形式分享下,同时 ...

  7. Android的各种Drawable 讲解 大全

    Android把可绘制的对象抽象为Drawable,不同的图形图像资源就代表着不同的drawable类型.Android FrameWork提供了一些具体的Drawable实现,通常在代码中都不会直接 ...

  8. android ViewPager滑动事件讲解

    首先ViewPager在处理滑动事件的时候要用到OnPageChangeListener OnPageChangeListener这个接口需要实现三个方法:(onPageScrollStateChan ...

  9. Android XListView实现原理讲解及分析

    XListview是一个非常受欢迎的下拉刷新控件,但是已经停止维护了.之前写过一篇XListview的使用介绍,用起来非常简单,这两天放假无聊,研究了下XListview的实现原理,学到了很多,今天分 ...

随机推荐

  1. 一个“”字引发的痛苦经历

    (一篇老文章,还有点价值,特意整理了一下.由于涉及客户项目,已经进行了脱敏处理) 1 写在前面的话 虽然这个问题是有解决方案的,但我不建议大家提供给客户,理由见此. 2 问题描述 2010.10.12 ...

  2. Java多线程其他

    1.interrupt()方法 interrupt方法不会真正中断线程,它只会清楚线程的wait,sleep,join的受阻状态,时线程重新获得CPU的执行权. 此时如果再次调用线程的wait,sle ...

  3. mac链接linux终端,shell脚本发布代码

    项目的业务需求:从mac端直接连上linux服务终端,并发布相关的代码 一.使用ssh链接上linux服务端 1.cd ~/.ssh 2.vi config,按照下面的内容配置config文件,然后: ...

  4. kafka学习笔记2:生产者

    这次的笔记主要记录一下kafka的生产者的使用和一些重要的参数. 文中主要截图均来自kafka权威指南 主要涉及到两个类KafkaProducer和ProducerRecord. 总览 生产者的主要架 ...

  5. 用户需求与NABCD分析

    用户需求与NABCD分析 目录 项目简介 用户需求分析 调研途径 问卷情况说明 问卷反馈与分析 NABCD分析 Need 需求 Approach 途径 Benefit 好处 Competitors 竞 ...

  6. CMSIS_RTOS_Tutorial自译中文版

    一.序言 本资料是Trevor Martin编写的<The Designers Guide to the Cortex-M Processor Family>的摘要,并得到Elsevier ...

  7. R语言高性能编程(三)

    一.使用并行计算加倍提升性能1.数据并行 VS 任务并行实现数据并行的算法scoket 并行性注意并行计算时间并不与执行任务的计算资源数目成正比(计算机核心),amdahl定律:并行代码的速度受限于串 ...

  8. python基础-------模块与包(三)正则表达式

    re模块正则表达式 正则表达式常用符号: [ re模块使用方法]: match(string[, pos[, endpos]]) | re.match(pattern, string[, flags] ...

  9. [转]Oracle 索引质量分析

    http://blog.csdn.net/leshami/article/details/23687137 索引质量的高低对数据库整体性能有着直接的影响.良好高质量的索引使得数据库性能得以数量级别的提 ...

  10. Zabbix服务网页报错汇总

    第1章 Zabbix简介及组成 1.1 zabbix简介 zabbix是一个基于web界面,提供分布式系统监视以及网络监视功能的企业级的开源解决方案.它可以监视各种网络参数,保证服务器自动的安全运营, ...