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

Posted 天耀106

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了动脑学院-手写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按钮的字符串信息则说明绑定成功了。



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



以上是关于动脑学院-手写ButterKnife框架(不包含自动生成代码)的主要内容,如果未能解决你的问题,请参考以下文章

手写ButterKnife

框架手写系列---apt注解处理器方式实现ButterKnife框架

动脑学院-网络请求框架

动脑学院-自适应屏幕布局

手写ButterKnife来搞明白Android注解处理器

手写ButterKnife来搞明白Android注解处理器