Android—简单路由框架实践

简单路由框架实现:

1.目录结构

        Android—简单路由框架实践

         Android—简单路由框架实践

 annotation和factory-compiler是两个java library,分别负责接口还有APT。

2.依赖关系

app作为主工程依赖所有

implementation project(':annotation')
implementation project(':router')
implementation project(':secondmodule')
annotationProcessor project(':factory-compiler')

secondmodule作为组件

implementation project(':annotation')
implementation project(path: ':router')
annotationProcessor project(':factory-compiler')

factory-compiler

implementation 'com.google.auto.service:auto-service:1.0-rc6'
implementation project(':annotation')
implementation 'com.squareup:javapoet:1.10.0'
annotationProcessor 'com.google.auto.service:auto-service:1.0-rc6'

3.在annotation中创建注解类

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.CLASS)
public @interface Router {
    String value();
}

4.使用注解

在app的MainActivity类类名打上注解

@Router(value = "MainActivity")

在secondmodule的SecondActivity类类名打上注解

@Router(value = "SecondActivity")

5.在router工程创建路由类

public class TextRouter {

    // 页面路由表
    private static final List<Path> paths = new ArrayList<>();

    // 将页面插入到路由表中
    public static void add(String path, Class<? extends Activity> activity) {
        paths.add(new Path(path, activity));
    }

    /**
     * 通过 router 打开 activity
     *
     * @param context
     * @param path
     */
    public static void navigate(Context context, String path, Bundle bundle) {
        // 遍历路由表,进行 uri 的匹配,匹配成功,则启动对面的 Activity 页面
        for (Path p : paths) {
            if (p.value.equals(path)) {
                Intent intent = new Intent(context, p.getActivity());
                intent.putExtra(path,bundle);
                context.startActivity(intent);
                return;
            }
        }
    }

    // 路由记录
    public static class Path {
        private final String value;
        private final Class<? extends Activity> activity;

        public Path(String path, Class<? extends  Activity> activity) {
            this.value = path;
            this.activity = activity;
        }

        public Class<? extends Activity> getActivity() {
            return activity;
        }
    }
}

我们只有通过该类的add方法添加进value值跟对应的Activity即可完成注册,当我们需要跳转到某个类时,就用navigate方法传入对应的value值就可以完成跳转。

接下来就可以用APT来实现对用上注解的Activity(既MainActivity跟SecondActivity)进行add操作。

6.在factory-compiler中创建Processer

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

    @Override
    public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
        String pkgName = null;
        // 首先获取注解元素
        Set<? extends Element> elements = roundEnvironment.getElementsAnnotatedWith(Router.class);

        if (elements.isEmpty()) return false;

        // 定义一个 public static 类型的 map 方法
        MethodSpec.Builder mapMethod = MethodSpec.methodBuilder("init").addModifiers(Modifier.PUBLIC, Modifier.FINAL, Modifier.STATIC);

        // 遍历注解元素
        for (Element element: elements) {
            if (element.getKind() == ElementKind.CLASS) {
                pkgName = String.valueOf(processingEnv.getElementUtils().getPackageOf(element).getQualifiedName());
                Router router = element.getAnnotation(Router.class);
                // 获取 activity 的 class name
                ClassName className = ClassName.get((TypeElement) element);
                // 获取 uri 地址
                String path = router.value();
                // 生成代码 Routers.map(uri, xxx.class);
                ClassName router1 = ClassName.get("com.example.router", " TextRouter");
                mapMethod.addStatement("$T.add($S, $T.class)",router1, path, className);
            }
        }

        mapMethod.addCode("\n");

        // 生成 RouterMapping 文件
        TypeSpec helloWorldClass = TypeSpec.classBuilder("RouterMapping")
                .addModifiers(Modifier.PUBLIC, Modifier.FINAL)
                .addMethod(mapMethod.build())
                .build();

        assert pkgName != null;
        JavaFile javaFile = JavaFile.builder(pkgName, helloWorldClass).build();

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

    }

    @Override
    public Set<String> getSupportedAnnotationTypes() {
        Set<String> annotations = new LinkedHashSet<>();
        annotations.add(Router.class.getCanonicalName());
        return annotations;
    }

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

Rebuild之后我们就可以看到编译生成的.java文件

Android—简单路由框架实践

Android—简单路由框架实践

 App工程下面也会生成

Android—简单路由框架实践

Android—简单路由框架实践 不过我们还需要调用RouterMapping.init()方法才能让这两个activity注册成功。可以选择在app的Application中完成初始化操作

public class TextApp extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        init();
        SecondModule.init();
    }

    private void init(){
        RouterMapping.init();
    }
}

secondmodule中的初始化 

public class SecondModule {

    public static void init(){
        RouterMapping.init();
    }
}

8.实现路由跳转

@Router(value = "MainActivity")
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        TextView tv = findViewById(R.id.tv);
        tv.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                   TextRouter.navigate(MainActivity.this,"SecondActivity", null);
            }
        });
    }

    @Override
    protected void onResume() {
        super.onResume();
    }
}

SecondActivity也是同样的操作即可跳转到MainActivity。

因为这里只示范了两个module的跳转,app作为主工程需要对其他子module进行初始化操作所以依赖了所有子工程,不过可以发现MainActivity在没有import入SecondModule的情况下也可以实现跳转,因此路由可以解决不相互依赖的组件之间相互跳转问题,只要在需要被跳转的类上进行注解。

上一篇:12个View绘制流程高频面试题,你掌握了多少


下一篇:中高级Android大厂面试秘籍,为你保驾护航金三银四,直通大厂(上