返回

Android APT系列 - 十分钟让你的AS动态生成代码

Android

前言

前天看了公司的路由框架源码后,打算自己手撸一套路由框架,决定不用反射,而用Apt来做,因为大名鼎鼎的ButterKnife/Dragger都是用Apt来实现,到底要看看有哪些好玩的地方。在这一篇文章中,我们使用APT来实现按钮的点击控制,也算是路由框架的一个铺垫。

正文

1. 准备工作

首先,你需要确保你的Android Studio已经安装了Apt插件。如果还没有,可以按照以下步骤进行安装:

  1. 打开Android Studio。
  2. 点击“文件”菜单,然后选择“设置”。
  3. 在“设置”对话框中,点击“插件”选项卡。
  4. 在“插件”选项卡中,搜索“Apt”,然后点击“安装”按钮。
  5. 等待Apt插件安装完成。

2. 创建注解处理器

现在,你可以开始创建自己的注解处理器了。为此,你需要创建一个新的Android项目。在项目中,创建一个名为“AptProcessor”的新包。在“AptProcessor”包中,创建一个名为“ButtonProcessor”的新类。这个类将作为你的注解处理器。

package com.example.aptprocessor;

import com.google.auto.service.AutoService;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.TypeSpec;

import javax.annotation.processing.*;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import java.io.IOException;
import java.util.Set;

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

    @Override
    public Set<String> getSupportedAnnotationTypes() {
        return Set.of(Button.class.getCanonicalName());
    }

    @Override
    public SourceVersion getSupportedSourceVersion() {
        return SourceVersion.latestSupported();
    }

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        for (Element element : roundEnv.getElementsAnnotatedWith(Button.class)) {
            TypeElement typeElement = (TypeElement) element.getEnclosingElement();
            String className = typeElement.getSimpleName().toString();
            String packageName = processingEnv.getElementUtils().getPackageOf(typeElement).toString();

            MethodSpec onClickMethod = MethodSpec.methodBuilder("onClick")
                    .addModifiers(Modifier.PUBLIC)
                    .returns(void.class)
                    .addParameter(android.view.View.class, "view")
                    .addStatement("android.util.Log.d(\"ButtonProcessor\", \"Button clicked!\");")
                    .build();

            TypeSpec typeSpec = TypeSpec.classBuilder(className + "$OnClickListener")
                    .addModifiers(Modifier.PUBLIC)
                    .addMethod(onClickMethod)
                    .build();

            JavaFile javaFile = JavaFile.builder(packageName, typeSpec).build();

            try {
                javaFile.writeTo(processingEnv.getFiler());
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return true;
    }
}

3. 创建注解

接下来,你需要创建一个注解来标注那些你想动态生成的代码。为此,你需要在“AptProcessor”包中创建一个名为“Button”的新类。这个类将作为你的注解。

package com.example.aptprocessor;

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

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
public @interface Button {
}

4. 使用注解

现在,你可以使用注解来标注那些你想动态生成的代码了。为此,你需要在你的代码中添加以下代码:

@Button
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Button button = findViewById(R.id.button);
        button.setOnClickListener(new MainActivity$OnClickListener() {
            @Override
            public void onClick(View view) {
                // Do something when the button is clicked.
            }
        });
    }
}

5. 编译代码

现在,你可以编译你的代码了。为此,你需要点击“构建”菜单,然后选择“构建项目”。

6. 运行代码

现在,你可以运行你的代码了。为此,你需要点击“运行”按钮。

7. 查看结果

现在,你可以查看结果了。为此,你需要在日志窗口中查找以下消息:

D/ButtonProcessor: Button clicked!

结语

恭喜你!你已经成功地使用Android APT动态生成了代码。现在,你可以开始学习更高级的APT技巧,比如如何使用APT来实现路由框架。