注释Android开发经验谈Android开发

Android Apt之Activity Route

2018-01-29  本文已影响83人  三十二蝉

前言

代码设计

  1. router-annotation(java library)
    这里java工程里面只放注解的声明类。这里只实现了两个注解RouterActivityRouterField
  2. router-compiler (java library)
    这个工程是编译期依赖的工程,作用是编译期扫描代码,根据RouterActivityRouterField这两个注解的使用,生成相关代码。这里需要讲下如何扫描代码并且生成代码的。这部分功能的实现主要依赖两个库:Google的auto-service(扫描代码),Squareup的javapoet(生成代码)
  3. router (android library)
    主要逻辑代码。在这个模块中会定义一些功能类和接口。router-compiler模块可以根据这些接口和功能类generate逻辑代码。需要注意的是router-compiler是不需要依赖router的,router-compiler是根据包名+类名的方式获取类的。

代码实现

router-annotation

RouterActivity是一个注解,用此注解修饰的Activity根据指定的路由地址,会自动添加到路由表中,当系统挂载了路由表之后,就可根据指定的路由地址来访问特定的Activity了。代码如下:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface RouterActivity {
    String[] value();
}

这里Activity可用多个路由地址修改。

RouterField是一个用于表示Activity跳转时参数传递的注解,用这个注解修饰的成员变量,表示为接收Intent参数的变量。

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RouterField {
    String[] value();
}

router-compiler

这个模块只包含一个类RouterProcessor,这个类的大致结构如下:

//此处用AutoService注解,就可实现编译期自动扫描代码
@AutoService(Processor.class)
public class RouterProcessor extends AbstractProcessor{
    private Elements elementUtils;
    private String targetModuleName = "";

    @Override
    public Set<String> getSupportedAnnotationTypes() {
        //支持的注解类型
        return Collections.singleton(RouterActivity.class.getCanonicalName());
    }

    @Override
    public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
      //处理代码扫描结果的关键函数
      ...
       return true;
    }

    @Override
    public synchronized void init(ProcessingEnvironment processingEnvironment) {
        super.init(processingEnvironment);
        //在扫描代码之前可从build.gradle中读取一些配置项
    }

    @Override
    public SourceVersion getSupportedSourceVersion() {
        //表示支持的Jdk版本
        return SourceVersion.RELEASE_7;
    }

}

下面分别讲解一下函数的实现:

  1. init函数
    我们的项目大多都是多module的形式,这时候我们就需要为每个module创建一个Activity路由注册表,然后在Application初始化的时候将所有的路由注册表挂载上,达到Activity路由跳转的目的。这里我们在init函数中,配置每个模块路由表的前缀名称。
 @Override
    public synchronized void init(ProcessingEnvironment processingEnvironment) {
        super.init(processingEnvironment);
        elementUtils = processingEnvironment.getElementUtils();
        Map<String, String> map = processingEnvironment.getOptions();
        Set<String> keys = map.keySet();
        for (String key: keys) {
            if ("targetModuleName".equals(key)) {
                this.targetModuleName = map.get(key);
            }
            System.out.println(key + " + " + map.get(key));

并在module的build.gradle文件下配置如下代码:

apt {
    arguments {
        targetModuleName 'moduleName'
    }
}
  1. process函数
    这个函数的大致流程如下:找到所有被RouterActivity修饰的Activity;实现router模块中的RouterInitializer接口,将每个Activity的路由地址加入路由表中;同时为每个Activity创建一个XXXActivityHelper(用于更友好的Activity调整),并将每个XXXAcitivyHelper放入RouterHelper中,提供get方法获取。process函数的具体实现,可详见项目源码(都是一些代码生成的语句,没有多少逻辑)。

router

代码使用

public class DemoApp extends Application {

    @Override
    public void onCreate() {
        super.onCreate();
        Router.init("demo");  //自定义scheme协议
    }
}
@RouterActivity({"main"})
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        findViewById(R.id.btn_second).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                RouterHelper.getSecondActivityHelper().start(MainActivity.this);
            }
        });
    }
}

@RouterActivity({"second"})
public class SecondActivity extends AppCompatActivity {
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);
    }
}

build目录生成的代码如下:


build目录生成代码

详细代码可查看:Github项目
现阶段代码还不完善,后期会添加更多功能。

上一篇 下一篇

猜你喜欢

热点阅读