动脑学院-手写ButterKnife框架(不包含自动生成代码)

1、目录结构


2、butterknife-annotions新增一个BindView接口

package lwl.tianyao.butterknife_annotions;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.SOURCE)
public @interface BindView {

    int value();
}

3、bufferknife-compiler 

1)build.gradle添加依赖


具体名称:

api 'com.google.auto.service:auto-service:1.0-rc3'
    implementation project(':butterknife-annotions')
tasks.withType(JavaCompiler){
    options.encoding = "UTF-8"
}

2)新建一个类ButterKnifeProcess继承AbstractProcessor

package lwl.tianyao.bufferknife_compiler;

import com.google.auto.service.AutoService;

import java.io.Writer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Filer;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.Processor;
import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.TypeMirror;
import javax.tools.JavaFileObject;

import lwl.tianyao.butterknife_annotions.BindView;

@AutoService(Processor.class)
public class ButterKnifeProcess extends AbstractProcessor {

    protected ProcessingEnvironment processingEnv;
    private boolean initialized = false;

    //1.我们要处理哪些注解
    @Override
    public Set<String> getSupportedAnnotationTypes() {
        Set<String> types= new LinkedHashSet<>();
        types.add(BindView.class.getCanonicalName());
        return types;
    }

    //2.添加支持JDK的支持
    @Override
    public SourceVersion getSupportedSourceVersion() {
        return SourceVersion.latestSupported();
    }

    //3.定义一个用生成java文件的对象
    Filer filer;
    @Override
    public synchronized void init(ProcessingEnvironment processingEnvironment) {
        super.init(processingEnvironment);
        processingEnv = processingEnvironment;
        filer=processingEnvironment.getFiler();
    }

    @Override
    public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
        //set保存了所有带注解的位置的相关信息

        //取到所有含有BindView注解的java文件的信息
        Set<? extends Element> elementSet = roundEnvironment.getElementsAnnotatedWith(BindView.class);
        //进行分类 key--类名 value --所有的成员变量
        Map<String,List<VariableElement>> cacheMap = new HashMap<>();
        for(Element element:elementSet){
            VariableElement variableElement = (VariableElement) element;
            String activityName = getActivityName(variableElement);
            List<VariableElement> list = cacheMap.get(activityName);
            //判断一下,是否以前有分类
            if(list==null){
                list = new ArrayList<>();
                cacheMap.put(activityName,list);
            }
            list.add(variableElement);
        }

        Iterator iterator = cacheMap.keySet().iterator();
        while (iterator.hasNext()){
            //准备生成的java文件的信息
            //1.Activity的名字
            String activity = (String) iterator.next();
            //2.获取当前activity中所有的成员
            List<VariableElement> cacheElements = cacheMap.get(activity);
            //3.获取包名
            String packageName = getPackageName(cacheElements.get(0));
            //4.获取要生成的文件的类名
            String newActivityBinder = activity+"$ViewBinder";

            Writer writer = null;
            try {
                JavaFileObject javaFileObject = filer.createSourceFile(newActivityBinder);
                writer = javaFileObject.openWriter();
                String activitySimpleName = cacheElements.get(0)
                        .getEnclosingElement().getSimpleName().toString()+"$ViewBinder";
                //写入文件中
                writer.write("package "+packageName+" ;");
                writer.write("\n");
                writer.write("import "+packageName+".ViewBinder;");
                writer.write("\n");
                writer.write("public class "+activitySimpleName+" implements ViewBinder<"+activity+">{");
                writer.write("\n");
                writer.write("public void bind("+activity+" target){");
                writer.write("\n");

                for(VariableElement variableElement:cacheElements){
                    BindView bindView = variableElement.getAnnotation(BindView.class);
                    //取到成员变量名
                    String fieldName = variableElement.getSimpleName().toString();
                    //取成员变量的类型
                    TypeMirror typeMirror = variableElement.asType();
                    writer.write("target."+fieldName+"=("+typeMirror.toString()+")target.findViewById("+bindView.value()+");");
                    writer.write("\n");
                }

                writer.write("}");
                writer.write("\n");
                writer.write("}");
                writer.write("\n");
                writer.close();



            }catch (Exception e){
                e.printStackTrace();
            }

        }

        return false;
    }

    private String getActivityName(VariableElement variableElement) {
        String packageName=this.getPackageName(variableElement);
        Element typeElement = variableElement.getEnclosingElement();
        return packageName+"."+typeElement.getSimpleName().toString();
    }

    private String getPackageName(VariableElement variableElement) {
        Element typeElement = variableElement.getEnclosingElement();
        String packageName = processingEnv.getElementUtils()
                .getPackageOf(typeElement)
                .getQualifiedName()
                .toString();
        return packageName;
    }
}

3)最终生成的java文件

package lwl.tianyao.bufferknifeproject ;
import lwl.tianyao.bufferknifeproject.ViewBinder;
public class MyActivity$ViewBinder implements ViewBinder<lwl.tianyao.bufferknifeproject.MyActivity>{
public void bind(lwl.tianyao.bufferknifeproject.MyActivity target){
target.btn=(android.widget.Button)target.findViewById(2131165218);
}
}

4、主项目

1)新增ViewBinder接口

package lwl.tianyao.bufferknifeproject;

public interface ViewBinder<T> {

    public void bind(T target);

}

2)新增ButterKnife类

package lwl.tianyao.bufferknifeproject;

import android.app.Activity;

public class ButterKnife {

    public static void bind(Activity activity){
        String className =activity.getClass().getName()+"$ViewBinder";
        try {
            Class<?> viewBindClass = Class.forName(className);
            ViewBinder viewBinder = (ViewBinder) viewBindClass.newInstance();
            viewBinder.bind(activity);
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

3)Acitivity的代码

package lwl.tianyao.bufferknifeproject;

import android.app.Activity;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

import lwl.tianyao.butterknife_annotions.BindView;

public class MyActivity extends Activity {

    @BindView(R.id.btn)
    Button btn;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);
    }

    public void click(View view){
        Toast.makeText(this,btn.toString(),Toast.LENGTH_SHORT).show();
    }

}

4)布局文件

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <Button
        android:onClick="click"
        android:id="@+id/btn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</android.support.constraint.ConstraintLayout>

最后一步,编译运行如果能正常显示btn按钮的字符串信息则说明绑定成功了。



代码下载地址: 点击打开链接



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值