ARouter使用自定义注解处理器,自动生成跳转Activity的代码,避免手动填写和管理path

Posted guangdeshishe

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ARouter使用自定义注解处理器,自动生成跳转Activity的代码,避免手动填写和管理path相关的知识,希望对你有一定的参考价值。

大家都知道ARouter要跳转目标Activity需要两步:

1.在Activity上添加Route注解

// Add annotations on pages that support routing (required)
// The path here needs to pay attention to need at least two levels : /xx/xx
@Route(path = "/test/activity")
public class YourActivity extend Activity 
    ...

2.执行ARouter.getInstance().build("/test/activity").navigation()方法即可实现跳转

// 1. Simple jump within application (Jump via URL in 'Advanced usage')
ARouter.getInstance().build("/test/activity").navigation();

// 2. Jump with param bundle
ARouter.getInstance().build("/test/1")
            .withBundle("key1", bundle)
            .navigation();

这就导致了我们需要去管理大量的path字符串,为什么ARouter不能在编译时期帮我们生成一个中间类去管理这些path字符串呢?

既然官方不支持那就自己来做一个吧,整体思路如下:

1.定义两个Activity并添加Route注解

@Route(path = "/login/LoginActivity")
class LoginActivity : AppCompatActivity() 
@Route(path = "/login/RegisterActivity")
class RegisterActivity :BaseActivity() 

2.通过自定义注解处理器,处理所有带Route注解的类,并取出注解里的path变量值,生成一个中间类用于管理所有的path,并封装跳转的方法,生成的中间类如下:

package com.agilezhu.processor.generate;

import android.os.Bundle;
import java.lang.String;

public final class ARouterPage 
  LoginActivity LoginActivity;

  RegisterActivity RegisterActivity;

  public ARouterPage() 
    LoginActivity.path = "/login/LoginActivity";
    RegisterActivity.path = "/login/RegisterActivity";
  

  public static class LoginActivity 
    public static String path;

    static 
      path= "/login/LoginActivity";
    

    public static void navigation(String key, Bundle params) 
      com.alibaba.android.arouter.launcher.ARouter.getInstance().build(path).withBundle(key,params).navigation();
    

    public static void navigation() 
      com.alibaba.android.arouter.launcher.ARouter.getInstance().build(path).navigation();
    
  

  public static class RegisterActivity 
    public static String path;

    static 
      path= "/login/RegisterActivity";
    

    public static void navigation(String key, Bundle params) 
      com.alibaba.android.arouter.launcher.ARouter.getInstance().build(path).withBundle(key,params).navigation();
    

    public static void navigation() 
      com.alibaba.android.arouter.launcher.ARouter.getInstance().build(path).navigation();
    
  


3.使用方法

//不带参数
ARouterPage.LoginActivity.navigation()
//带Bundle类型参数
ARouterPage.RegisterActivity.navigation("params",Bundle())
//也可以使用原有ARouter跳转方式携带各种参数
ARouter.getInstance().build(ARouterPage.LoginActivity.path).withBoolean("key",true).navigation();

有了注解处理器相当于自动帮我们生成了一个管理所有path的类:

  • 可以通过类似调用目标Activity的方式进行跳转;
  • 简化了ARouter跳转Acticity的代码;
  • 每次添加、修改、删除对应的类,都不需要手动修改管理类代码;

注解处理器开发过程

  1. 添加一个java 类型Module

  2. build.gradle 内容如下:

    plugins 
        id 'java-library'
    
    dependencies 
        implementation fileTree(dir: 'libs', include: ['*.jar'])
        annotationProcessor 'com.google.auto.service:auto-service:1.0-rc7'//auto-service本身也是个注解处理器
        implementation 'com.google.auto.service:auto-service:1.0-rc7'//注解 processor 类,并对其生成 META-INF 的配置信息
        implementation 'com.squareup:javapoet:1.13.0' //通过类调用的形式来生成java代码,避免手动拼接字符串
        implementation "com.alibaba:arouter-annotation:1.0.6"
    
    
    
    java 
        sourceCompatibility = JavaVersion.VERSION_1_7
        targetCompatibility = JavaVersion.VERSION_1_7
    
    
  3. 注解处理器核心类:

    package com.agilezhu.processor;
    
    import com.alibaba.android.arouter.facade.annotation.Route;
    import com.google.auto.service.AutoService;
    import com.squareup.javapoet.ClassName;
    import com.squareup.javapoet.CodeBlock;
    import com.squareup.javapoet.JavaFile;
    import com.squareup.javapoet.MethodSpec;
    import com.squareup.javapoet.TypeSpec;
    
    import java.util.LinkedHashSet;
    import java.util.Set;
    
    import javax.annotation.processing.AbstractProcessor;
    import javax.annotation.processing.Filer;
    import javax.annotation.processing.Messager;
    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.Modifier;
    import javax.lang.model.element.TypeElement;
    import javax.lang.model.util.Elements;
    import javax.tools.Diagnostic;
    
    /**
     * Generate ARouterPage.java for ARouter
     */
    @AutoService(Processor.class)
    public class ARouterProcessor extends AbstractProcessor 
        private Filer mFiler; //文件相关工具类:用于保存生成的java类文件
        private Elements mElementUtils; //元素相关工具类:用于获取java类文件
        private Messager mMessager;//用于打印日志
    
        @Override
        public synchronized void init(ProcessingEnvironment processingEnvironment) 
            super.init(processingEnvironment);
            mFiler = processingEnv.getFiler();
            mElementUtils = processingEnv.getElementUtils();
            mMessager = processingEnv.getMessager();
        
    
        @Override
        public Set<String> getSupportedAnnotationTypes() 
            //返回该注解处理器能够处理哪些注解
            Set<String> types = new LinkedHashSet<>();
            types.add(Route.class.getName());
            return types;
        
    
        @Override
        public SourceVersion getSupportedSourceVersion() 
            //返回当前注解处理器支持的java版本号
            return SourceVersion.latest();
        
    
        @Override
        public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) 
            if (set == null || set.size() == 0) 
                return false;
            
            //将要生成的java完整类名
            String targetClassName = "ARouterPage";
            String packageName = "com.agilezhu.processor.generate";
    
            //创建方法(构造方法)
            MethodSpec.Builder bindMethodBuilder = MethodSpec.methodBuilder("<init>")
                    .addModifiers(Modifier.PUBLIC);
    
            //创建类
            TypeSpec.Builder aRouterPageClassBuilder = TypeSpec.classBuilder(targetClassName)
                    .addModifiers(Modifier.PUBLIC, Modifier.FINAL);
    
            //获取所有的源码文件
            Set<? extends Element> elements = roundEnvironment.getRootElements();
            for (Element element : elements) 
                if (!(element instanceof TypeElement)) //判断是否class类
                    continue;
                
                //转换成class类型
                TypeElement typeElement = (TypeElement) element;
                //当前文件的类名
                String classSimpleName = element.getSimpleName().toString();
                Route routeAnnotation = element.getAnnotation(Route.class);
                if (routeAnnotation == null) 
                    continue;
                
                mMessager.printMessage(Diagnostic.Kind.WARNING, "myProcess=====>>>>>" + classSimpleName);
    
                ClassName innerClassName = ClassName.get(packageName, targetClassName, classSimpleName);
    
                try 
                    aRouterPageClassBuilder.addField(innerClassName, classSimpleName)
                            .addType(TypeSpec.classBuilder(innerClassName.simpleName())
                                    .addModifiers(Modifier.STATIC, Modifier.PUBLIC)
                                    .addField(String.class, "path", Modifier.PUBLIC, Modifier.STATIC)
                                    .addStaticBlock(CodeBlock.builder().addStatement("path= \\"" + routeAnnotation.path() + "\\"").build())
                                    .addMethod(MethodSpec
                                            .methodBuilder("navigation")
                                            .addParameter(String.class,"key")
                                            .addParameter(ClassName.get("android.os","Bundle"), "params")
                                            .addStatement("com.alibaba.android.arouter.launcher.ARouter.getInstance().build(path).withBundle(key,params).navigation()")
                                            .addModifiers(Modifier.PUBLIC, Modifier.STATIC)
                                            .build())
                                    .addMethod(MethodSpec
                                            .methodBuilder("navigation")
                                            .addStatement("com.alibaba.android.arouter.launcher.ARouter.getInstance().build(path).navigation()")
                                            .addModifiers(Modifier.PUBLIC, Modifier.STATIC)
                                            .build())
                                    .build());
                 catch (Exception e) 
                    e.printStackTrace();
                
    
                //构造方法中添加初始化代码
                bindMethodBuilder.addStatement(classSimpleName + ".path = \\"" + routeAnnotation.path() + "\\"");
            
            aRouterPageClassBuilder.addMethod(bindMethodBuilder.build());
            //创建java文件
            JavaFile bindProxyFile = JavaFile
                    .builder(packageName, aRouterPageClassBuilder.build())
                    .build();
            try 
                //保存java类文件
                bindProxyFile.writeTo(mFiler);
             catch (Throwable e) 
                e.printStackTrace();
            
            return false;
        
    
    
    
  4. 业务模块中引用:

    kapt project(path: ':lib:processor') //这里用的kapt处理Kotlin代码
    
  5. 重新编译后,在当前模块build/generated/source/kapt/debug/com/agilezhu/processor/generate/ARouterPage.java路径下就能看到生成的类

模块代码下载

以上是关于ARouter使用自定义注解处理器,自动生成跳转Activity的代码,避免手动填写和管理path的主要内容,如果未能解决你的问题,请参考以下文章

ARouter使用自定义注解处理器,自动生成跳转Activity的代码,避免手动填写和管理path

Arouter之注解处理器

ARouter源码分析

路由框架-ARouter(跳转拦截)

ARouter的原理

Android 组件化路由组件 ( 页面跳转参数依赖注入 )