前言

在前面的Android6.0权限处理不再复杂文章中,介绍过一个开源框架PermissionsDispatcher(权限调度者)框架,基于该框架的条件下,有了介绍注解以及注解APT的两篇文章,分别是:

Android进阶之Annotation(注解)的使用

Android编译时,怎么自动生成代码?

【Android编译时,怎么自动生成代码?】这篇文章的结尾中,提到过可以使用JavaPoet来优雅的生成代码。那今天我们的主要内容就是来介绍一下【JavaPoet】该开源框架。

环境的搭建

1,新建项目名为【myJavaPoet】的Android项目;
2,在其中新建Module名为【poet】的模块,选择【Java Library】,如下:

Java Library

PS:

JavaPoet必须在Java Library中使用,例如在rt.jar包中的javax包属于Android核心库中没有,所以不能直接在app Module和Android Library中使用,必须要创建一个Java Library,然后由Java Library导出jar包使用,如下图:

rt.jar

3,在【poet.build.gradle】中,添加如下信息:

dependencies {    compile 'com.squareup:javapoet:1.8.0'}

完成后的项目目录结构如下:

项目目录结构

下面开始讲例子,希望看例子的时候,注释切记一定要多注意看~~~

例子1,PoetHello

主要讲的是类、方法的生成,在其中添加修饰、返回类型、抽象方法,以及如何写入文件系统等等。。。

PoetHello的代码如下:

package com.example;import com.squareup.javapoet.JavaFile;import com.squareup.javapoet.MethodSpec;import com.squareup.javapoet.TypeSpec;import java.io.File;import javax.lang.model.element.Modifier;/** * 使用JavaPoet写一个Hello 2017/4/24 11:01 */public class PoetHello {    /**     * 生成器 2017/4/24 14:49     */    public static void product() {        try {            // 创建方法 2017/4/24 14:26            MethodSpec method = MethodSpec.methodBuilder("hello")                    .addModifiers(Modifier.PUBLIC) // 修饰符                    .returns(String.class) // 返回类型                    .addParameter(String.class, "name", Modifier.FINAL) // 添加final参数 2017/4/25 09:03                    .addStatement("String say") // 负责分号、换行 2017/4/24 14:52                    .addStatement("say = $S + name", "Hello ")                    .addStatement("return say")                    .build();            // 抽象方法 2017/4/24 17:03            MethodSpec abstractMethod = MethodSpec.methodBuilder("abstractHello")                    .addModifiers(Modifier.ABSTRACT, Modifier.PROTECTED)                    .build();            // 创建类            TypeSpec hello = TypeSpec.classBuilder("Hello")                    .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)                    .addMethod(method) // 添加方法                    .addMethod(abstractMethod)                    .build();            // 写入文件系统 2017/4/24 14:27            JavaFile javaFile = JavaFile.builder("com.example.all_product", hello)                    .build();            javaFile.writeTo(new File("poet/src/main/java")); // 指定文件路径        } catch (Exception e) {            e.printStackTrace();        }    }    public static void main(String[] args) {        PoetHello.product();    }}

生成的Hello.java类,代码如下:

package com.example.all_product;import java.lang.String;public abstract class Hello {  public String hello(String name) {    String say;    say = "Hello " + name;    return say;  }  protected abstract void abstractHello();}

例子2,PoetFor

主要讲的就是beginControlFlow() 、endControlFlow()的配合使用,提供换行符与缩进。以for循环为例子,其它使用方法类似,如if、while、switch等等。。。

其中还有$S、$T、$N、$L的使用,意思分别如下:

$S for Strings

顾名思义,$S代表的是String,将其看成是一个字符创即可。

$T for Types

这里的Type/类型,其实可以简单的理解成我们的Class类即可。

$N for Names

可以理解成引用另一个变量名即可。

$L for Literals

这个刚开始其实是比较不好理解,但场景使用多了就应该慢慢能理解了,在这里其实就可以简单的理解成【Formatter】即可。

PoetFor代码如下(切记看注释):

package com.example;import com.squareup.javapoet.FieldSpec;import com.squareup.javapoet.JavaFile;import com.squareup.javapoet.MethodSpec;import com.squareup.javapoet.TypeSpec;import java.io.File;import javax.lang.model.element.Modifier;/** * 生成for代码 2017/4/24 14:57 */public class PoetFor {    /**     * for循环生成器 2017/4/24 14:57     */    public static void product(int from, int to) {        try {            // 创建全局字段,并初始化 2017/4/25 09:15            FieldSpec fieldSpec = FieldSpec.builder(String.class, "DESC")                    .addModifiers(Modifier.PRIVATE, Modifier.STATIC, Modifier.FINAL)                    .initializer("$S", "Sum is ")                    .build();            // 生成方法 2017/4/24 15:09            MethodSpec methodSpec = MethodSpec.methodBuilder("forInteger")                    .addModifiers(Modifier.PUBLIC, Modifier.STATIC)                    .returns(void.class) // 无返回值                    .addStatement("int sum = 0")                    // beginControlFlow() + endControlFlow() 需要一起使用,提供换行符和缩进。 2017/4/24 15:09                    // $L 占位符,类似于Formatter,替换int类型 2017/4/24 15:25                    .beginControlFlow("for (int i = $L; i <= $L; i++)", from, to)                    .addStatement("sum += i")                    .endControlFlow()                    // $T 替换类名   $S 替换字符串 2017/4/24 15:31                    // 使用System会自动import使用 2017/4/24 15:34                    .addStatement("$T.out.println($N + sum)", System.class, "DESC")                    .build();            // 类生成 2017/4/24 15:10            TypeSpec typeSpec = TypeSpec.classBuilder("ForInteger")                    .addModifiers(Modifier.PUBLIC)                    .addMethod(methodSpec)                    .addField(fieldSpec)                    .build();            // 文件生成 2017/4/24 15:10            JavaFile javaFile = JavaFile.builder("com.example.all_product", typeSpec)                    .addFileComment("JavaPoet生成For循环代码 2017/4/24 15:07")                    .build();            javaFile.writeTo(new File("poet/src/main/java"));        } catch (Exception e) {            e.printStackTrace();        }    }    public static void main(String[] args) {        PoetFor.product(0, 10);    }}

生成的ForInteger.java类如下:

// JavaPoet生成For循环代码 2017/4/24 15:07package com.example.all_product;import java.lang.String;import java.lang.System;public class ForInteger {  private static final String DESC = "Sum is ";  public static void forInteger() {    int sum = 0;    for (int i = 0; i <= 10; i++) {      sum += i;    }    System.out.println(DESC + sum);  }}

例子3,PoetList

主要讲的是ClassName的硬指定,以及引用指定;然后再讲了使用ParameterizedTypeName.get(ClassName, ClassName)创建List泛型的使用。

PoetList的代码如下:

package com.example;import com.example.all_product.ForInteger;import com.squareup.javapoet.ClassName;import com.squareup.javapoet.JavaFile;import com.squareup.javapoet.MethodSpec;import com.squareup.javapoet.ParameterizedTypeName;import com.squareup.javapoet.TypeName;import com.squareup.javapoet.TypeSpec;import java.io.File;import javax.lang.model.element.Modifier;/** * 使用ClassName(重要),生成List代码 2017/4/24 16:04 */public class PoetList {    /**     * 生成器 2017/4/24 16:04     */    public static void product() {        try {            // list泛型的类型 2017/4/24 16:06            ClassName type = ClassName.get("com.example.all_product", "ForInteger");            // List类型            ClassName list = ClassName.get("java.util", "List");            // ArrayList类型            ClassName arrayList = ClassName.get("java.util", "ArrayList");            // 生成泛型类型,类型的名称、参数的名称 2017/4/24 16:08            TypeName listType = ParameterizedTypeName.get(list, type);            MethodSpec methodSpec = MethodSpec.methodBuilder("listType")                    .addModifiers(Modifier.PUBLIC, Modifier.STATIC)                    .returns(listType)                    .addStatement("$T lstHello = new $T<>()", listType, arrayList)                    // ClassName类的绝对路径,内部利用该路径进行反射获取实体类,使用场景是当该类也是生成类时,可以硬指定 2017/4/24 16:18                    .addStatement("lstHello.add(new $T())", type) // ClassName指定                    .addStatement("lstHello.add(new $T())", ForInteger.class) // 引用指定                    .addStatement("return lstHello")                    .build();            TypeSpec typeSpec = TypeSpec.classBuilder("ListType")                    .addModifiers(Modifier.PUBLIC)                    .addMethod(methodSpec)                    .build();            JavaFile javaFile = JavaFile.builder("com.example.all_product", typeSpec)                    .build();            javaFile.writeTo(new File("poet/src/main/java"));        } catch (Exception e) {            e.printStackTrace();        }    }    public static void main(String[] args) {        PoetList.product();    }}

生成的ListType.java类,代码如下:

package com.example.all_product;import java.util.ArrayList;import java.util.List;public class ListType {  public static List listType() {    List lstHello = new ArrayList<>();    lstHello.add(new ForInteger());    lstHello.add(new ForInteger());    return lstHello;  }}

例子4,PoetMap

上面例子3讲的是List的使用,那么下面再来讲一下Map的创建使用。

PoetMap的代码如下:

package com.example;import com.squareup.javapoet.ClassName;import com.squareup.javapoet.JavaFile;import com.squareup.javapoet.MethodSpec;import com.squareup.javapoet.ParameterizedTypeName;import com.squareup.javapoet.TypeName;import com.squareup.javapoet.TypeSpec;import java.io.File;import javax.lang.model.element.Modifier;/** * 使用ClassName(重要),生成Map代码 2017/4/25 13:39 */public class PoetMap {    /**     * 生成器 2017/4/25 13:39     */    public static void product() {        try {            // list泛型的类型 2017/4/24 16:06            ClassName type = ClassName.get("com.example.all_product", "ForInteger");            // key 2017/4/25 13:38            ClassName string = ClassName.get("java.land", "String");            // map类型            ClassName map = ClassName.get("java.util", "Map");            // HashMap类型            ClassName hashMap = ClassName.get("java.util", "HashMap");            // 生成Map类型,类型的名称、Key、Value 2017/4/25 14:08            TypeName listType = ParameterizedTypeName.get(map, string, type);            MethodSpec methodSpec = MethodSpec.methodBuilder("listType")                    .addModifiers(Modifier.PUBLIC, Modifier.STATIC)                    .returns(listType)                    .addStatement("$T mapHello = new $T<>()", listType, hashMap)                    .addStatement("mapHello.put($S, new $T())", "key", type)                    .addStatement("return mapHello")                    .build();            TypeSpec typeSpec = TypeSpec.classBuilder("MapType")                    .addModifiers(Modifier.PUBLIC)                    .addMethod(methodSpec)                    .build();            JavaFile javaFile = JavaFile.builder("com.example.all_product", typeSpec)                    .build();            javaFile.writeTo(new File("poet/src/main/java"));        } catch (Exception e) {            e.printStackTrace();        }    }    public static void main(String[] args) {        PoetMap.product();    }}

生成的MapType.java,代码如下:

package com.example.all_product;import java.util.HashMap;import java.util.Map;public class MapType {  public static Map listType() {    Map mapHello = new HashMap<>();    mapHello.put("key", new ForInteger());    return mapHello;  }}

例子5,PoetInterface

该例子讲的是利用JavaPoet来生成接口,使用的是TypeSpec.interfaceBuilder(InterfaceName)方法来创建接口类,也可以使用TypeSpec中的其它方法来创建枚举、注解等等。。。

PoetInterface的代码如下:

package com.example;import com.squareup.javapoet.FieldSpec;import com.squareup.javapoet.JavaFile;import com.squareup.javapoet.MethodSpec;import com.squareup.javapoet.TypeSpec;import java.io.File;import javax.lang.model.element.Modifier;/** * 生成接口 2017/4/25 09:16 */public class PoetInterface {    /**     * 生成器 2017/4/25 09:40     */    public static void product() {        try {            // 生成方法,必须有Modifier.ABSTRACT或STATIC 2017/4/25 09:25            MethodSpec methodSpec = MethodSpec.methodBuilder("getName")                    .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)                    .addJavadoc("获取名称\n") // 添加注释 2017/4/25 11:24                    .returns(String.class)                    .build();            // 生成字段,必须同时有Modifier.STATIC, Modifier.FINAL 2017/4/25 09:31            FieldSpec fieldSpec = FieldSpec.builder(String.class, "name")                    .addModifiers(Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL)                    .initializer("$S", "CCB")                    .build();            // interfaceBuilder方法标志生成接口类 2017/4/25 09:25            TypeSpec typeSpec = TypeSpec.interfaceBuilder("UserInterface")                    .addModifiers(Modifier.PUBLIC)                    .addMethod(methodSpec)                    .addField(fieldSpec)                    .build();            // 写入文件            JavaFile javaFile = JavaFile.builder("com.example.all_product", typeSpec)                    .addFileComment("Poet生成接口 2017/4/25 09:24")                    .build();            javaFile.writeTo(new File("poet/src/main/java"));        } catch (Exception e) {            e.printStackTrace();        }    }    public static void main(String[] args) {        PoetInterface.product();    }}

生成的UserInterface.java接口类,代码如下:

// Poet生成接口 2017/4/25 09:24package com.example.all_product;import java.lang.String;public interface UserInterface {  String name = "CCB";  /**   * 获取名称   */  String getName();}

例子6,PoetSort

主要讲的就是怎么创建匿名类。该例子先自动创建一个实体,再引用该实体类做sort排序。

PoetSort的代码如下:

package com.example;import com.squareup.javapoet.ClassName;import com.squareup.javapoet.FieldSpec;import com.squareup.javapoet.JavaFile;import com.squareup.javapoet.MethodSpec;import com.squareup.javapoet.ParameterizedTypeName;import com.squareup.javapoet.TypeSpec;import java.io.File;import java.util.Collections;import javax.lang.model.element.Modifier;/** * 写匿名类进行排序 2017/4/25 09:39 */public class PoetSort {    public static void product() {        try {            // 生成实体 2017/4/25 09:41            TypeSpec typeEntity = TypeSpec.classBuilder("UserEntity")                    .addModifiers(Modifier.PUBLIC)                    .addField(FieldSpec.builder(String.class, "name")                            .addModifiers(Modifier.PRIVATE)                            .build())                    .addMethod(MethodSpec.methodBuilder("getName")                            .addModifiers(Modifier.PUBLIC)                            .returns(String.class)                            .addStatement("return this.$N", "name")                            .build())                    .addMethod(MethodSpec.methodBuilder("setName")                            .addModifiers(Modifier.PUBLIC)                            .addParameter(String.class, "name")                            .returns(void.class)                            .addStatement("this.$N = $N", "name", "name")                            .build())                    .addField(FieldSpec.builder(int.class, "time")                            .addModifiers(Modifier.PRIVATE)                            .build())                    .addMethod(MethodSpec.methodBuilder("getTime")                            .addModifiers(Modifier.PUBLIC)                            .returns(int.class)                            .addStatement("return this.$N", "time")                            .build())                    .build();            // 写入用户实体 2017/4/25 09:48            JavaFile javaUserEntity = JavaFile.builder("com.example.all_product", typeEntity)                    .build();            javaUserEntity.writeTo(new File("poet/src/main/java"));            // 生成排序匿名类 2017/4/25 09:49            ClassName classComparator = ClassName.get("java.util", "Comparator"); // 指向Comparator            ClassName classList = ClassName.get("java.util", "List"); // 指向List            ClassName classUser = ClassName.get("com.example.all_product", "UserEntity"); // 指向User实体            // 匿名比对类 2017/4/25 09:52            TypeSpec typeCompare = TypeSpec.anonymousClassBuilder("")                    .addSuperinterface(ParameterizedTypeName.get(classComparator, classUser))                    .addMethod(MethodSpec.methodBuilder("compare")                            .addAnnotation(Override.class) // 添加注解 2017/4/25 10:56                            .addModifiers(Modifier.PUBLIC)                            .addParameter(classUser, "obj1")                            .addParameter(classUser, "obj2")                            .returns(int.class)                            .beginControlFlow("if ($N.$N() > $N.$N())",                                    "obj1", "getTime", "obj2", "getTime")                            .addStatement("return 1")                            .endControlFlow()                            .beginControlFlow("else if ($N.$N() < $N.$N())",                                    "obj1", "getTime", "obj2", "getTime")                            .addStatement("return -1")                            .endControlFlow()                            .beginControlFlow("else")                            .addStatement("return 0")                            .endControlFlow()                            .build())                    .build();            // 外部类 2017/4/25 09:59            TypeSpec typeSort = TypeSpec.classBuilder("UserSort")                    .addModifiers(Modifier.PUBLIC)                    .addMethod(MethodSpec.methodBuilder("sort")                            .addModifiers(Modifier.PUBLIC)                            .returns(void.class)                            .addParameter(ParameterizedTypeName.get(classList, classUser), "lstUsers")                            .addStatement("$T.sort($N, $L)", Collections.class, "lstUsers", typeCompare)                            .build())                    .build();            // 写入排序类 2017/4/25 10:03            JavaFile javaUserSort = JavaFile.builder("com.example.all_product", typeSort)                    .build();            javaUserSort.writeTo(new File("poet/src/main/java"));        } catch (Exception e) {            e.printStackTrace();        }    }    public static void main(String[] args) {        PoetSort.product();    }}

生成的UserEntity.java和UserSort.java类的代码如下:

package com.example.all_product;import java.lang.String;public class UserEntity {  private String name;  private int time;  public String getName() {    return this.name;  }  public void setName(String name) {    this.name = name;  }  public int getTime() {    return this.time;  }}
package com.example.all_product;import java.lang.Override;import java.util.Collections;import java.util.Comparator;import java.util.List;public class UserSort {  public void sort(List lstUsers) {    Collections.sort(lstUsers, new Comparator() {      @Override      public int compare(UserEntity obj1, UserEntity obj2) {        if (obj1.getTime() > obj2.getTime()) {          return 1;        }        else if (obj1.getTime() < obj2.getTime()) {          return -1;        }        else {          return 0;        }      }    });  }}

例子7,PoetExtend

主要就讲一下怎么使用superclass(ClassName)的方法来创建继承的子类,同理,也可以使用addSuperinterface(ClassName)的方法来创建实现接口,实现接口后,怎么重写接口的方法,可参考例子5。。。

PoetExtend的代码如下:

package com.example;import com.squareup.javapoet.ClassName;import com.squareup.javapoet.FieldSpec;import com.squareup.javapoet.JavaFile;import com.squareup.javapoet.MethodSpec;import com.squareup.javapoet.TypeSpec;import java.io.File;import javax.lang.model.element.Modifier;/** * 生成继承的子类 2017/4/25 14:48 */public class PoetExtend {    public static void product() {        try {            // 生成实体 2017/4/25 14:48            TypeSpec typeEntity = TypeSpec.classBuilder("SubUserEntity")                    .addModifiers(Modifier.PUBLIC)                    // 继承UserEntity类 2017/4/25 14:58                    .superclass(ClassName.get("com.example.all_product", "UserEntity"))                    // 实现UserInterface接口                    .addSuperinterface(ClassName.get("com.example.all_product", "UserInterface"))                    .addField(FieldSpec.builder(int.class, "id")                            .addModifiers(Modifier.PRIVATE)                            .build())                    .addMethod(MethodSpec.methodBuilder("getId")                            .addModifiers(Modifier.PUBLIC)                            .returns(int.class)                            .addStatement("return this.$N", "id")                            .build())                    .build();            // 写入用户实体 2017/4/25 14:55            JavaFile javaUserEntity = JavaFile.builder("com.example.all_product", typeEntity)                    .build();            javaUserEntity.writeTo(new File("poet/src/main/java"));        } catch (Exception e) {            e.printStackTrace();        }    }    public static void main(String[] args) {        PoetExtend.product();    }}

生成的SubUserEntity代码如下:

package com.example.all_product;public class SubUserEntity extends UserEntity implements UserInterface {  private int id;  public int getId() {    return this.id;  }}

总结

怎么动态的生成java代码,我们今天主要讲7个例子就好了,在我们写项目时,如果需要动态生成代码时,这应该足够应付80%的开发工作了,如果需要深入创建更复杂的代码,请移步参考JavaPoet开源框架。

结合前面几篇文章,就已经包含了创建注解、注解解析、代码生成,慢慢。。。慢慢。。。我们向自己写框架靠近。。。其实框架中经常使用的还有另一个检查工具,lint。我们可以自定义lint的检查规则,不过,我现在有一个地方卡住了,还没解决,后面如果解决了,有机会就一并讲一下。

今天就讲到这里了。。。

谢谢支持~~~

更多相关文章

  1. android 破解软件
  2. Android(安卓)里的FrameBuffer
  3. Android热更新框架Nuwa的使用
  4. egret 发布android原生项目(一)打包apk
  5. Android开发学习笔记:浅谈GridView
  6. Android之WebView安全
  7. Android(安卓)studio 快捷键汇总
  8. Android实现应用开机自启动
  9. Android(安卓)开发ListView适配器优化

随机推荐

  1. Android中将Activity转换成View使用.
  2. Android 7.0,8.0拍照loadXmlMetaData(XXXX
  3. android 加载圆形头像框
  4. Android(安卓)Bitmap处理
  5. android download file by stream
  6. Android 学习系列 - Java 多线程
  7. Android 返回键实现home键的功能
  8. Android中PopupWindow的使用
  9. android 音乐播放工具类MediaPlayer
  10. android上方显示进度的进度条