目录

  1. 【Android】注解框架(一)-- 基础知识Java 反射
  2. 【Android】注解框架(二)-- 基础知识(Java注解)& 运行时注解框架
  3. 【Android】注解框架(三)-- 编译时注解,手写ButterKnife
  4. 【Android】注解框架(四)-- 一行代码注入微信支付

apt介绍

作为Android程序员应该绝大部分分人都用过ButterKnife,Retrofit等框架,这些框架只需要在用的时候使用注解,就可以直接使用了,非常方便。并且这些框架并没有减少性能。

那么这些框架做了哪些东西呢?

我们以ButterKnife为例:

@BindView(R.id.textview)TextView textview;private Unbinder bind;@Overrideprotected void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    setContentView(R.layout.activity_main);    bind = ButterKnife.bind(this);    textview.setText("dfjslafjsalfls");}@Overrideprotected void onDestroy() {    bind.unbind();    super.onDestroy();}

上面是我们平常使用的时候所使用的代码,这些代码到底做了什么呢?

  1. 我们给元素写上注解
  2. 在编译器执行的环节,系统收集我们所写注解的元素,并将这些元素组合成Java代码MainActivity_ViewBinding
  3. 当我们调用ButterKnife.bind的时候,通过动态注入的方式,将MainActivityMainActivity_ViewBinding关联起来,并给所有的注解所在的元素赋值。

而这些东西的核心就是在编译期间生成我们所需要的Java文件,这样我们在使用的时候就基本没有性能的影响。

网上找到的APT的流程图:

手写ButterKnife

通过上面的图我们先生成这些module

butterknife_流程图

app - 主项目
butterknife - android lib
annotaion - java lib
compiler - java lib

在这些module的配置文件中配置

  1. project的build.gradle

    // 如果你的gradle版本是3.0以上则不需要配置buildscript {        repositories {        google()        jcenter()        mavenCentral()    }    dependencies {        classpath 'com.android.tools.build:gradle:3.0.0'        classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'    }}allprojects {    repositories {        google()        jcenter()        mavenCentral()    }}
  2. butterknife-compiler的build.gradle

    添加auto-service和javapoet这两个lib是用来方便我们生成Java代码的。

    auto-service: https://github.com/google/auto
    javapoet: http://blog.csdn.net/crazy1235/article/details/51876192

    dependencies {    implementation fileTree(include: ['*.jar'], dir: 'libs')    compile 'com.google.auto.service:auto-service:1.0-rc3'    compile 'com.squareup:javapoet:1.8.0'    implementation project(':butterknife-annotations')}
  3. app的build.gradle

    // gradle版本小于3.0apply plugin: 'com.neenbedankt.android-apt'compile project(':butterknife')compile project(':butterknife-annotations')apt project(':butterknife-compiler')// gradle版本大于3.0compile project(':butterknife')compile project(':butterknife-annotations')annotationProcessor project(':butterknife-compiler')

在annotation中写上注解

@Target(ElementType.FIELD)@Retention(RetentionPolicy.CLASS)public @interface BindView {    int value();}

在compiler中编写注解生成器

java文档: http://www.yq1012.com/api/index.html-overview-summary.html
javax.annotation.processing包
javax.lang.model.element包

  1. 创建类processor继承AbstractProcessor

    @AutoService(Processor.class)public class ButterKnifeProcessor extends AbstractProcessor {    private Elements elementUtils;    private Filer filer;    @Override    public synchronized void init(ProcessingEnvironment processingEnvironment) {        super.init(processingEnvironment);        elementUtils = processingEnvironment.getElementUtils();        filer = processingEnvironment.getFiler();    }    // 指定SourceVersion    @Override    public SourceVersion getSupportedSourceVersion() {        return SourceVersion.latestSupported();    }        }
  2. 指定我们所需要的annotation

    // 指定processortypepublic Set getSupportedAnnotationTypes() {    Set types = new LinkedHashSet<>();    Set> supportedAnnotations = getSupportedAnnotations();    for (Class<? extends Annotation> supportedAnnotation : supportedAnnotations) {        types.add(supportedAnnotation.getCanonicalName());    }    return types;}private Set> getSupportedAnnotations() {    Set> annotations = new LinkedHashSet<>();    annotations.add(BindView.class);    return annotations;}
  3. 在process中处理annotation

    首先将所有获取到的BindView细分到每个Activity中

    Set<? extends Element> elements = roundEnvironment.getElementsAnnotatedWith(BindView.class);// 将获取到的bindview细分到每个classMap> elementMap = new LinkedHashMap<>();for (Element element : elements) {    // 返回activity    Element enclosingElement = element.getEnclosingElement();    List bindViewElements = elementMap.get(enclosingElement);    if (bindViewElements == null) {        bindViewElements = new ArrayList<>();        elementMap.put(enclosingElement, bindViewElements);    }    bindViewElements.add(element);}

    通过遍历的方式处理每个细分的Activity

    // 生成代码for (Map.Entry> entrySet : elementMap.entrySet()) {    Element enclosingElement = entrySet.getKey();    List bindViewElements = entrySet.getValue();    // public final class xxxActivity_ViewBinding implements Unbinder    // 获取activity的类名    String activityClassNameStr = enclosingElement.getSimpleName().toString();    System.out.println("------------->" + activityClassNameStr);    ClassName activityClassName = ClassName.bestGuess(activityClassNameStr);    ClassName unBinderClassName = ClassName.get("com.fastaoe.butterknife", "Unbinder");    TypeSpec.Builder classBuilder =            TypeSpec.classBuilder(activityClassNameStr + "_ViewBinding")                    .addModifiers(Modifier.FINAL, Modifier.PUBLIC)                    .addSuperinterface(unBinderClassName)                    // 添加属性 private MainActivity target;                    .addField(activityClassName, "target", Modifier.PRIVATE);    // unbind()    ClassName callSuperClassName = ClassName.get("android.support.annotation", "CallSuper");    MethodSpec.Builder unbindMethodBuilder = MethodSpec.methodBuilder("unbind")            .addAnnotation(Override.class)            .addAnnotation(callSuperClassName)            .addModifiers(Modifier.PUBLIC, Modifier.FINAL);    // 构造函数    MethodSpec.Builder constructorMethodBuilder = MethodSpec.constructorBuilder()            .addParameter(activityClassName, "target")            .addModifiers(Modifier.PUBLIC)            // this.target = target            .addStatement("this.target = target");    for (Element bindViewElement : bindViewElements) {        // textview        String fieldName = bindViewElement.getSimpleName().toString();        // Utils        ClassName utilsClassName = ClassName.get("com.fastaoe.butterknife", "Utils");        // R.id.textview        int resourceId = bindViewElement.getAnnotation(BindView.class).value();        // target.textview = Utils.findViewById(target, R.id.textview)        constructorMethodBuilder.addStatement("target.$L = $T.findViewById(target, $L)", fieldName, utilsClassName, resourceId);        // target.textview = null        unbindMethodBuilder.addStatement("target.$L = null", fieldName);    }    classBuilder.addMethod(unbindMethodBuilder.build())            .addMethod(constructorMethodBuilder.build());    // 获取包名    String packageName = elementUtils.getPackageOf(enclosingElement).getQualifiedName().toString();    try {        JavaFile.builder(packageName, classBuilder.build())                .addFileComment("自己写的ButterKnife生成的代码,不要修改!!!")                .build().writeTo(filer);    } catch (IOException e) {        e.printStackTrace();    }}

在butterknife中编写注入代码

public class ButterKnife {    public static Unbinder bind(Activity activity) {        try {            Class<? extends Unbinder> bindClazz = (Class<? extends Unbinder>)                    Class.forName(activity.getClass().getName() + "_ViewBinding");            // 构造函数            Constructor<? extends Unbinder> bindConstructor = bindClazz.getDeclaredConstructor(activity.getClass());            Unbinder unbinder = bindConstructor.newInstance(activity);            return unbinder;        } catch (Exception e) {            e.printStackTrace();        }        return Unbinder.EMPTY;    }}

使用

我们的使用方式就和正真的ButterKnife一样了:

public class MainActivity extends AppCompatActivity {    @BindView(R.id.textview)    TextView textview;    private Unbinder bind;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        bind = ButterKnife.bind(this);        textview.setText("修改后的文字");    }    @Override    protected void onDestroy() {        bind.unbind();        super.onDestroy();    }}

最后

附上代码

更多相关文章

  1. Android中的人脸检测的示例代码(静态和动态)
  2. Android(安卓)TextView文字链接4中方法
  3. android 使用eclipse编译 FBReaderJ流程
  4. 谷歌Android为何关闭源代码?
  5. Android内核和驱动篇-Android内核介绍
  6. android文件存储
  7. mono for android 百度map binding项目
  8. Android中设置控件透明度的方法
  9. Android(安卓)简介:Android(安卓)SDK 和开发框架简介

随机推荐

  1. 用tcpdump抓取Android的网络数据包
  2. Android(安卓)SVG动画PathView源码解析与
  3. android濡備綍鍒╃敤aspectj杩涜AOP 缂
  4. android 的gradle
  5. Android初始化过程
  6. Android(安卓)Studio 添加arr为依赖
  7. 把第三方jar库加入android framework ser
  8. Android(安卓)TextWatcher鐩戞帶EditText
  9. 使用LocationManager来获取移动设备所在
  10. ANDROID 返回,菜单和HOME键的监听