项目源码:小小虫/APTDemo
1.背景
当我们项目进行组件化之后,那么难免会碰到一个问题,那就是组件之间的通信。例如下面的图,App里有两个组件(可以理解为两个Activity),视频录制组件(下面简称组件A)和视频播放组件(下面简称组件B)等,那么如何在App中调用起组件A,组件B,或者在组件A中如何调用组件B呢?
2.问题
问题一:App中调用起组件A,组件B
- 把所有组件全部引入(通过
implementation project
)到App主工程中,然后通过startActivity方法自然可以调用组件A,组件B的功能
问题二:组件A中如何调用组件B
- 在组件A中引入组件B,然后通过startActivity调用组件B的功能
利弊
- 优点:简单,方便调用代码
- 缺点:App与组件,组件与组件之间存在耦合,不方便扩展与拆分。例如:如果后面需求有变动,组件A中不需要调用组件B,那么你就需要把与组件B的交互删除。
解决方法
- 创建一个全局的LiveData,存储每个Activity的全类名,通过全类名启动
Intent intent = new Intent(); intent.seClassName(mContext,"com.example。MainActivity"); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); mContext.startActivity(intent);
- (目前主流)通过APT(注解处理器)技术,它用来在编译时扫描和处理注解。简单来说就是在编译期,通过注解采集信息,生成.java文件。减少重复的代码的编写。
例如需要跳转到某个Activity:
Router.getInstance().find("Activity自定义名字").navigate(this)
实现主要步骤:- 创建一个Router单例类,用来存储需要跳转的Activity类
private Map<String, String> activityMap; public void registerRoute(String activityName, String cls) { if (cls != null && !TextUtils.isEmpty(activityName)) { activityMap.put(activityName, cls); } }
- 利用APT技术生成Java文件,把所有需要跳转的Activity生成出来。如下就是用APT技术生成的文件:
public class AppRouterInit implements IRouterComponent{ @Override public void init() { cn.yzwill.router.Router.getInstance().registerRoute("/Activity/TrainClassList", "cn.yzwill.android.school.view.TrainClassActivity"); } }
- 反射调用生成的Java文件
上面我们生成的AppRouterInit文件,此时还没有加载进内存中,我们需要去调用它的init方法。
在Application的onCreate中我们初始化Router时,就会通过反射调用AppRouterInit的init方法。
public class MyApplication extends Application { @Override public void onCreate() { super.onCreate(); Router.getInstance().init(this); } }
反射调用(这里我们暂时写死):public void init(Context context) { mContext = context; try { Class<?> aClass = Class.forName("cn.yzwill.router.generate.AppRouterInit"); if (IRouterComponent.class.isAssignableFrom(aClass)) { IRouterComponent iRouter = (`IRouterComponent`) aClass.newInstance(); iRouter.init(); } } catch ( Exception e) { e.printStackTrace(); } }
- 创建一个Router单例类,用来存储需要跳转的Activity类
2.创建APT工程
APT目录结构
2.1 创建lib_router
- 提供一个对外的接口类,给app或者其他组件做跳转。例如
Router.getInstance().find("/Activity/EditCircle").navigate(this)
2.2 创建lib_router-annotation
提供给app或者其他组件需要做跳转的Activity打上一个标记,例如:
@RouterPath("/Activity/EditCircle")
class HotTopicEditCircleActivity
RouterPath源码:
@Target(ElementType.TYPE)
public @interface RouterPath {
String value();
}
2.3 创建lib_router-compile
下面都是一些固定操作
1.在build.gradle中配置
apply plugin: 'java-library'
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
annotationProcessor 'com.google.auto.service:auto-service:1.0-rc4'
compileOnly 'com.google.auto.service:auto-service:1.0-rc4'
//需要处理的自定义注解
implementation project(':lib_router-annotation')
}
java {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
2.创建生成代码文件类
注意:记得标注@AutoService(Processor.class)
才会被系统调用
@AutoService(Processor.class)
public class PathProcessor extends AbstractProcessor {
@Override
public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
return false;
}
}
2.4 引入自定义注解器
在需要被处理注解的模块中引入注解器和相关库,例如:在App的build.gradle中引入
dependencies {
implementation project(path: ':lib_router')
implementation project(path: ':lib_router-annotation')
annotationProcessor project(path: ':lib_router-compiler')
}
3.总结
到这里,APT项目的创建就完成了,下一章讲解如何在PathProcessor中生成我们需要的代码文件。