/**
 * <pre>
 *     @author 杨充
 *     blog  : https://github.com/yangchong211
 *     time  : 2017/06/21
 *     desc  : 一定time时间内该点击事件只能执行一次
 *     revise:
 * </pre>
 */
//@Retention用来修饰这是一个什么类型的注解。这里表示该注解是一个编译时注解。
@Retention(RetentionPolicy.CLASS)
//@Target用来表示这个注解可以使用在哪些地方。
// 比如:类、方法、属性、接口等等。这里ElementType.METHOD 表示这个注解可以用来修饰:方法
@Target(ElementType.METHOD)
//这里的interface并不是说OnceClick是一个接口。就像申明类用关键字class。申明注解用的就是@interface。
public @interface OnceClick {
    //返回值表示这个注解里可以存放什么类型值
    int value();
}
/**
 * <pre>
 *     @author 杨充
 *     blog  : https://github.com/yangchong211
 *     time  : 2017/06/21
 *     desc  : 自定义Processor编译器
 *     revise:
 * </pre>
 */
@SupportedSourceVersion(SourceVersion.RELEASE_7)
public class OnceClickProcessor extends AbstractProcessor {
    private Messager messager;
    private Elements elementUtils;
    @Override
    public synchronized void init(ProcessingEnvironment processingEnv) {
        super.init(processingEnv);
        messager = processingEnv.getMessager();
        elementUtils = processingEnv.getElementUtils();
    }
    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        //获取proxyMap
        Map<String, OnceProxyInfo> proxyMap = getProxyMap(roundEnv);
        //遍历proxyMap,并生成代码
        for (String key : proxyMap.keySet()) {
            OnceProxyInfo proxyInfo = proxyMap.get(key);
            writeCode(proxyInfo);
        }
        return true;
    }
    @Override
    public Set<String> getSupportedAnnotationTypes() {
        Set<String> types = new LinkedHashSet<>();
        types.add(OnceClick.class.getCanonicalName());
        return types;
    }
    @Override
    public SourceVersion getSupportedSourceVersion() {
        return super.getSupportedSourceVersion();
    }
}
apply plugin: ‘java-library‘
dependencies {
    implementation fileTree(dir: ‘libs‘, include: [‘*.jar‘])
    implementation ‘com.google.auto.service:auto-service:1.0-rc3‘
    implementation ‘com.squareup:javapoet:1.10.0‘
    implementation project(‘:OnceClickAnnotation‘)
}
sourceCompatibility = "7"
targetCompatibility = "7"
public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //初始化OnceClick,并设置点击事件间隔是2秒
        OnceInit.once(this,2000);
    }
    @OnceClick(R.id.tv_1)
    public void Click1(){
        Log.d("tag--------------------","tv_1");
    }
    @OnceClick(R.id.tv_2)
    public void Click2(View v){
        Log.d("tag--------------------","tv_2");
    }
}

// 编译生成的代码,不要修改
// 更多内容:https://github.com/yangchong211
package com.ycbjie.ycapt;
import android.view.View;
import com.ycbjie.api.Finder;
import com.ycbjie.api.AbstractInjector;
public class MainActivity$$_Once_Proxy<T extends MainActivity> implements AbstractInjector<T> {
    public long intervalTime; 
    @Override 
    public void setIntervalTime(long time) {
        intervalTime = time;
    } 
    @Override 
    public void inject(final Finder finder, final T target, Object source) {
        View view;
        view = finder.findViewById(source, 2131165325);
        if(view != null){
            view.setOnClickListener(new View.OnClickListener() {
            long time = 0L;
            @Override
            public void onClick(View v) {
                long temp = System.currentTimeMillis();
                if (temp - time >= intervalTime) {
                    time = temp;
                    target.Click1();
                }
            }});
        }
        view = finder.findViewById(source, 2131165326);
        if(view != null){
            view.setOnClickListener(new View.OnClickListener() {
            long time = 0L;
            @Override
            public void onClick(View v) {
                long temp = System.currentTimeMillis();
                if (temp - time >= intervalTime) {
                    time = temp;
                    target.Click2(v);
                }
            }});
        }
  }
}
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
    //获取proxyMap
    Map<String, OnceProxyInfo> proxyMap = getProxyMap(roundEnv);
    //遍历proxyMap,并生成代码
    for (String key : proxyMap.keySet()) {
        OnceProxyInfo proxyInfo = proxyMap.get(key);
        //写入代码
        writeCode(proxyInfo);
    }
    return true;
}
public class OnceProxyInfo {
    
    private String packageName;
    private String targetClassName;
    private String proxyClassName;
    private TypeElement typeElement;
    private List<OnceMethod> methods;
    private static final String PROXY = "_Once_Proxy";
    OnceProxyInfo(String packageName, String className) {
        this.packageName = packageName;
        this.targetClassName = className;
        this.proxyClassName = className + "$$" + PROXY;
    }
    String getProxyClassFullName() {
        return packageName + "." + proxyClassName;
    }
    String generateJavaCode() throws OnceClickException {
        StringBuilder builder = new StringBuilder();
        builder.append("// 编译生成的代码,不要修改\n");
        builder.append("// 更多内容:https://github.com/yangchong211\n");
        builder.append("package ").append(packageName).append(";\n\n");
        //写入导包
        builder.append("import android.view.View;\n");
        builder.append("import com.ycbjie.api.Finder;\n");
        builder.append("import com.ycbjie.api.AbstractInjector;\n");
        builder.append(‘\n‘);
        builder.append("public class ").append(proxyClassName)
                .append("<T extends ").append(getTargetClassName()).append(">")
                .append(" implements AbstractInjector<T>").append(" {\n");
        builder.append(‘\n‘);
        generateInjectMethod(builder);
        builder.append(‘\n‘);
        builder.append("}\n");
        return builder.toString();
    }
    private String getTargetClassName() {
        return targetClassName.replace("$", ".");
    }
    private void generateInjectMethod(StringBuilder builder) throws OnceClickException {
        builder.append("    public long intervalTime; \n");
        builder.append(‘\n‘);
        builder.append("    @Override \n")
                .append("    public void setIntervalTime(long time) {\n")
                .append("        intervalTime = time;\n    } \n");
        builder.append(‘\n‘);
        builder.append("    @Override \n")
                .append("    public void inject(final Finder finder, final T target, Object source) {\n");
        builder.append("        View view;");
        builder.append(‘\n‘);
        //这一步是遍历所有的方法
        for (OnceMethod method : getMethods()) {
            builder.append("        view = ")
                    .append("finder.findViewById(source, ")
                    .append(method.getId())
                    .append(");\n");
            builder.append("        if(view != null){\n")
                    .append("            view.setOnClickListener(new View.OnClickListener() {\n")
                    .append("            long time = 0L;\n");
            builder.append("            @Override\n")
                    .append("            public void onClick(View v) {\n");
            builder.append("                long temp = System.currentTimeMillis();\n")
                    .append("                if (temp - time >= intervalTime) {\n" +
                            "                    time = temp;\n");
            if (method.getMethodParametersSize() == 1) {
                if (method.getMethodParameters().get(0).equals("android.view.View")) {
                    builder.append("                    target.")
                            .append(method.getMethodName()).append("(v);");
                } else {
                    throw new OnceClickException("Parameters must be android.view.View");
                }
            } else if (method.getMethodParametersSize() == 0) {
                builder.append("                    target.")
                        .append(method.getMethodName()).append("();");
            } else {
                throw new OnceClickException("Does not support more than one parameter");
            }
            builder.append("\n                }\n")
                    .append("            }")
                    .append("});\n        }\n");
        }
        builder.append("  }\n");
    }
    TypeElement getTypeElement() {
        return typeElement;
    }
    void setTypeElement(TypeElement typeElement) {
        this.typeElement = typeElement;
    }
    List<OnceMethod> getMethods() {
        return methods == null ? new ArrayList<OnceMethod>() : methods;
    }
    void addMethod(OnceMethod onceMethod) {
        if (methods == null) {
            methods = new ArrayList<>();
        }
        methods.add(onceMethod);
    }
}
public class OnceMethod {
    private int id;
    private String methodName;
    private List<String> methodParameters;
    OnceMethod(int id, String methodName, List<String> methodParameters) {
        this.id = id;
        this.methodName = methodName;
        this.methodParameters = methodParameters;
    }
    int getMethodParametersSize() {
        return methodParameters == null ? 0 : methodParameters.size();
    }
    int getId() {
        return id;
    }
    String getMethodName() {
        return methodName;
    }
    List<String> getMethodParameters() {
        return methodParameters;
    }
}
原文:https://www.cnblogs.com/yc211/p/10445926.html