思考集中方式实现:
方式一:使用EventBus,缺点:太多bean
方式二:使用广播 缺点:少用
方式三:隐式意图:缺点:配置太麻烦<intent-filter> <action android:name="com.example.android.tst.SecondActivity"/> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> Intent intent=new Intent("com.example.android.tst.SecondActivity");
方式四:使用类加载方式 缺点,写错报名类名
Class activityClass= Class.forName("");找到class字节码文件 new Intent(this,activityClass);
方式五:使用全局Map方式
类加载的封装
自己去每个类都要在Application手动注册到map,难维护,一下几百行;
原理:Arouter 像路由表注册分组和路径,向路由表查找并交互
生成两个类,一个类的HashMap,key为group,value为组下类;这个类HashMap,key为path,存放具体路径
预备点:java层级的工具,编译器干活,扫描全局注解
名称 | 作用 | |
---|---|---|
APT | Annotation Processing Tool | 根据规则,生成代码,类文件 |
JavaPoet | 面向对象思维OOP: 先写方法放到类里面,再丢到包里面这样倒序的方式 |
ARouter 通过 Apt 技术,生成保存路径(路由 path)和被注解(@Router)的组件类的映 射关系的类,利用这些保存了映射关系的类,Arouter 根据用户的请求 postcard(明信片) 寻找到要跳转的目标地址(class),使用 Intent 跳转。
Group: key=="app" value="ARouter$$Path$$app" --------- /app/MainActivity
Path: key=="/app/MainActivity" value="MainActivity.class的封装类 RouterBean"
最终的效果:Group
public class ARouter$$Group$$personal implements ARouterGroup {
@Override
public Map<String, Class<? extends ARouterPath>> getGroupMap() {
Map<String, Class<? extends ARouterPath>> groupMap = new HashMap<>();
groupMap.put("personal", ARouter$$Path$$personal.class);
return groupMap;
}
}
最终的效果:Path
public class ARouter$$Path$$personal implements ARouterPath {
@Override
public Map<String, RouterBean> getPathMap() {
Map<String, RouterBean> pathMap = new HashMap<>();
pathMap.put("/personal/Personal_Main2Activity", RouterBean.create();
pathMap.put("/personal/Personal_MainActivity", RouterBean.create());
return pathMap;
}
}
运行时注解反射处理
XUtil
编译器注解反射处理
EventBus -传统方式一行一行生成
Dagger2
Room
alibaba/Arouter - javapoet
ButterKnife - javapoet 优雅
DataBinding
// AutoService则是固定的写法,加个注解即可
// 通过auto-service中的@AutoService可以自动生成AutoService注解处理器,用来注册
// 用来生成 META-INF/services/javax.annotation.processing.Processor 文件
@AutoService(Processor.class)
// 允许/支持的注解类型,让注解处理器处理
@SupportedAnnotationTypes({
ProcessorConfig.AROUTER_PACKAGE})
// 指定JDK编译版本
@SupportedSourceVersion(SourceVersion.RELEASE_7)
// 注解处理器接收的参数
@SupportedOptions({
ProcessorConfig.OPTIONS, ProcessorConfig.APT_PACKAGE})
public class ARouterProcessor extends AbstractProcessor {
// 操作Element的工具类(类,函数,属性,其实都是Element)
private Elements elementTool;
// type(类信息)的工具类,包含用于操作TypeMirror的工具方法
private Types typeTool;
// Message用来打印 日志相关信息
private Messager messager;
// 文件生成器, 类 资源 等,就是最终要生成的文件 是需要Filer来完成的
private Filer filer;
private String options;
// 做初始化工作,就相当于 Activity中的 onCreate函数一样的作用
@Override
public synchronized void init(ProcessingEnvironment processingEnvironment) {
super.init(processingEnvironment);
elementTool = processingEnvironment.getElementUtils();
messager = processingEnvironment.getMessager();
filer = processingEnvironment.getFiler();
// 只有接受到 App壳 传递过来的书籍,才能证明我们的 APT环境搭建完成
options = processingEnvironment.getOptions().get(ProcessorConfig.OPTIONS);
String aptPackage = processingEnvironment.getOptions().get(ProcessorConfig.APT_PACKAGE);
messager.printMessage(Diagnostic.Kind.NOTE, ">>>>>>>>>>>>>>>>>>>>>> options:" + options);
messager.printMessage(Diagnostic.Kind.NOTE, ">>>>>>>>>>>>>>>>>>>>>> aptPackage:" + aptPackage);
if (options != null && aptPackage != null) {
messager.printMessage(Diagnostic.Kind.NOTE, "APT 环境搭建完成....");
} else {
messager.printMessage(Diagnostic.Kind.NOTE, "APT 环境有问题,请检查 options 与 aptPackage 为null...");
}
}
/**
* 相当于main函数,开始处理注解
* 注解处理器的核心方法,处理具体的注解,生成Java文件
*
* @param set 使用了支持处理注解的节点集合
* @param roundEnvironment 当前或是之前的运行环境,可以通过该对象查找的注解。
* @return true 表示后续处理器不会再处理(已经处理完成)
*/
@Override
public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
if (set.isEmpty()) {
messager.printMessage(Diagnostic.Kind.NOTE, "并没有发现 被@ARouter注解的地方呀");
return false;
}
// 获取所有被 @ARouter 注解的 元素集合
Set<? extends Element> elements = roundEnvironment.getElementsAnnotatedWith(ARouter.class);
// 遍历所有的类节点
for (Element element : elements) {
// 获取类节点,获取包节点 (com.xiangxue.xxxxxx)
String packageName = elementTool.getPackageOf(element).getQualifiedName().toString();
// 获取简单类名,例如:MainActivity
String className = element.getSimpleName().toString();
messager.printMessage(Diagnostic.Kind.NOTE, ">>>>>>>>>>>>>> 被@ARetuer注解的类有:" + className); // 打印出 就证明APT没有问题
// 下面是练习 JavaPoet
/**
* package com.example.helloworld;
*
* public final class HelloWorld {
* public static void main(String[] args) {
* System.out.println("Hello, JavaPoet!");
* }
* }
*/
// 下毒,现在是 无法生成 【作业】
// 1.方法
/*MethodSpec mainMethod = MethodSpec.methodBuilder("main")
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
.returns(void.class)
.addParameter(String[].class, "args")
.addStatement("$T.out.println($S)", System.class, "Hello, JavaPoet!")
.build();
// 2.类
TypeSpec helloWorld = TypeSpec.classBuilder("HelloWorld")
.addModifiers(Modifier.PUBLIC, Modifier.FINAL)
.addMethod(mainMethod)
.build();
// 3.包
JavaFile packagef = JavaFile.builder("com.derry.study", helloWorld).build();
// 去生成
try {
packagef.writeTo(filer);
} catch (IOException e) {
e.printStackTrace();
messager.printMessage(Diagnostic.Kind.NOTE, "生成失败,请检查代码...");
}*/
// 先JavaPoet 写一个简单示例,方法--->类--> 包,是倒序写的思路哦
/*
package com.example.helloworld;
public final class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello, JavaPoet!");
}
}
*/
// 方法
MethodSpec mainMethod = MethodSpec.methodBuilder("main")
.addModifiers(Modifier.PUBLIC, Modifier.FINAL)
.returns(void.class)
.addParameter(System[].class, "args")
// 增加main方法里面的内容
.addStatement("$T.out.println($S)", System.class, "AAAAAAAAAAA!")
.build();
// 类
TypeSpec testClass = TypeSpec.classBuilder("Test")
.addMethod(mainMethod)
.addModifiers(Modifier.PUBLIC, Modifier.FINAL)
.build();
// 包
// Program type already present: com.xiangxue.test22.Test
JavaFile packagef = JavaFile.builder("com.xiangxue.test22", testClass).build();
try {
packagef.writeTo(filer);
} catch (IOException e) {
e.printStackTrace();
messager.printMessage(Diagnostic.Kind.NOTE, "生成Test文件时失败,异常:" + e.getMessage());
}
}
return true; // 坑:必须写返回值,表示处理@ARouter注解完成
}
}
@paramter
String name; //在字段添加注解
public class Personal_MainActivity$$Parameter implements ParameterGet {
@Override
public void getParameter(Object targetParameter) {
Personal_MainActivity t = (Personal_MainActivity) targetParameter;
t.name = t.getIntent().getStringExtra("name");
t.sex = t.getIntent().getStringExtra("sex");
}
}
common 层继承标准规则
,定义具体业务标准规则具体实现
交给具体组件访问
Arouter 的优化:ASM字节码插桩:设计就是遍历所有classes.dex,所有的源码 ,双重遍历加到缓存里面,非常耗时;
Native与H5的问题:因为在H5中是无法使用StartActivity()跳转到Native页面的,而从Native跳转到H5页面也只能通过配置浏览器的方式实现。
1.通俗易懂又全面
2.开源最佳实践
3.中文ARouter使用API
4.最详细的ARouter源码分析
5.Gradle自定义插件,热修复asm字节码插桩