The use of APT in the componentization of Android development

What is APT?

APT(Annotation Processing Tool)

It is a tool for processing annotations. It detects the annotations in the source code file and automatically produces code based on the annotations. If you want a custom annotation processor to run normally, it must be processed through the APT tool. It can also be understood that only after the APT tool is declared, the custom annotation interpreter can be executed during the compilation of the program.

Popular understanding: according to the rules, help us generate code and generate class files

Android Studio 3.4.1 + Gradle5.1.1 (recommended version)

How to use APT in componentization?

Component development is for decoupling and high isolation. Each module is independent. If we want to achieve direct interaction between each component, we can use the following methods:

  • Reflection reflection technology can be successful, the maintenance cost is high, and high version @hide restrictions are prone to appear
  • There are many EvenTBus EventBeans (one-to-one), and one-to-many will be messy and difficult to maintain (I haven't tried this)
  • The cost of implicit intent maintenance is okay, but it is more troublesome and requires too many actions in the Manifest to be maintained
  • BroadCastReceiver requires dynamic registration (after 7.0), and the needy party sends a broadcast
  • Class loading requires an accurate path to the full class name, the maintenance of the original version is relatively high, and it is prone to human error

Then say so much, mainly to say that APT is one of the best solutions for interaction in componentized development.

So how to use it?

First, take the interface jump between various components as an example:

The interface jump between the main page module (MainActivity) and the order module (OrderActivity):

One, create a new annotation class

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.CLASS)//RetentionPolicy.CLASS 编译期预编译的操作
public @interface ARouter {

    //详细路由器路径(必填),如:"/app/MainActivity"
    String path();

    // 从path中截取出来
    String group() default "";
}

2. Create a new ARouterProcessor to inherit AbstractProcessor to implement annotation work

ARouterProcessor inherits AbstractProcessor, to the class with ARouter annotation, a new class is generated for interactive use during compilation


@AutoService(Processor.class)
@SupportedAnnotationTypes("com.goodboy.annotation.ARouter")
@SupportedSourceVersion(SourceVersion.RELEASE_7)
@SupportedOptions("content")
public class ARouterProcessor extends AbstractProcessor {

    //操作Element工具类
    private Elements elementUtils;

    //type(类信息)工具类
    private Types typeUtils;

    //用来输出警告,错误等日志
    private Messager messager;

    //文件生成器
    private Filer filer;

    @Override
    public synchronized void init(ProcessingEnvironment processingEnvironment) {
        super.init(processingEnvironment);
        elementUtils = processingEnvironment.getElementUtils();
        typeUtils = processingEnvironment.getTypeUtils();
        messager = processingEnvironment.getMessager();
        filer = processingEnvironment.getFiler();

        String content = processingEnvironment.getOptions().get("content");
        messager.printMessage(Diagnostic.Kind.NOTE,content);
    }

    @Override
    public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
        if (set.isEmpty())return false;

        //获取项目中所有使用使用了ARouter注解的节点
        Set<? extends Element> elements = roundEnvironment.getElementsAnnotatedWith(ARouter.class);
        //遍历所有的类节点
        for (Element element : elements) {
            //类节点之上,就是包节点
            String packageName = elementUtils.getPackageOf(element).getQualifiedName().toString();
            //获取简单类名
            String className = element.getSimpleName().toString();
            messager.printMessage(Diagnostic.Kind.NOTE,"被注解的类有:" + className);
            // 最终我们想要生成的类文件 如:MainActivity$$ARouter
            String finalClassName = className + "$$ARouter";
            // 公开课写法,也是EventBus写法(https://github.com/greenrobot/EventBus)
            try {
                // 创建一个新的源文件(Class),并返回一个对象以允许写入它
                JavaFileObject sourceFile = filer.createSourceFile(packageName + "." + finalClassName);
                // 定义Writer对象,开启写入
                Writer writer = sourceFile.openWriter();
                // 设置包名
                writer.write("package " + packageName + ";\n");

                writer.write("public class " + finalClassName + " {\n");

                writer.write("public static Class<?> findTargetClass(String path) {\n");

                // 获取类之上@ARouter注解的path值
                ARouter aRouter = element.getAnnotation(ARouter.class);

                writer.write("if (path.equals(\"" + aRouter.path() + "\")) {\n");

                writer.write("return " + className + ".class;\n}\n");

                writer.write("return null;\n");

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

                // 最后结束别忘了
                writer.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return true;
    }
}

3. Add this annotation to the MainActivity and OrderActivity classes, and use the generated class to jump to the
MainActivity code

@ARouter(path = "/app/MainActivity")
public class MainActivity extends AppCompatActivity {

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


    public void jump(View view){
        Class<?> targetClass = OrderActivity$$ARouter.findTargetClass("/app/OrderActivity");
        startActivity(new Intent(this, targetClass));
    }
}

OrderActivity code


@ARouter(path = "/app/OrderActivity")
public class OrderActivity extends AppCompatActivity {

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_order);
        Log.d("mile", "--->OrderActivity");
    }

    public void jump(View view) {
        Class<?> targetClass = MainActivity$$ARouter.findTargetClass("/app/MainActivity");
        startActivity(new Intent(this, targetClass));
    }
}

Summary: Component development is to dynamically use APT to generate interoperable classes

Guess you like

Origin blog.csdn.net/yanwenyuan0304/article/details/106020717