简单路由框架实现:
1.目录结构
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文件
App工程下面也会生成
不过我们还需要调用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的情况下也可以实现跳转,因此路由可以解决不相互依赖的组件之间相互跳转问题,只要在需要被跳转的类上进行注解。