回顾一下之前的调用逻辑。在JavaPoet APT(二)
中我们能用的跳转是这个样子
public void jumpPersonal(View view) {
// 以前是这样跳转
/*Intent intent = new Intent(this, Personal_MainActivity.class);
intent.putExtra("name", "David");
startActivity(intent);*/
// 现在是这样跳转 目前还要写这么多代码,是不是非常累
// TODO 最终的成效:用户 一行代码搞定,同时还可以传递参数,同时还可以懒加载
ARouter$$Group$$personal group$$personal = new ARouter$$Group$$personal();
Map<String, Class<? extends ARouterPath>> groupMap = group$$personal.getGroupMap();
Class<? extends ARouterPath> myClass = groupMap.get("personal");
try {
ARouter$$Path$$personal path = (ARouter$$Path$$personal) myClass.newInstance();
Map<String, RouterBean> pathMap = path.getPathMap();
RouterBean bean = pathMap.get("/personal/Personal_MainActivity");
if (bean != null) {
Intent intent = new Intent(this, bean.getMyclass());
startActivity(intent);
}
} catch (Exception e) {
e.printStackTrace();
}
}
对于普通调用者来说过于复杂,我们的设计及目标是一行代码,多个参数搞定。
1.动态生成懒加载参数接收。
我们使用的时候模仿ButterKnife
@ARouter(path = "/personal/Personal_MainActivity")
public class Personal_MainActivity extends AppCompatActivity {
@Parameter
String name;
@Parameter
String sex;
...
}
目标生成的代码模板:
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");
}
}
arouter_annotation 添加注解Parameter
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.CLASS)
public @interface Parameter {
// 不填写name的注解值表示该属性名就是key,填写了就用注解值作为key
// 从getIntent()方法中获取传递参数值
String name() default "";
}
标准规则的定义arouter_api-----ParameterGet
public interface ParameterGet {
/**
* 目标对象.属性名 = getIntent().属性类型... 完成赋值操作
*
* @param targetParameter 目标对象:例如:MainActivity 中的那些属性
*/
void getParameter(Object targetParameter);
}
arouter_compiler 编写注解处理器生成我们的模板代码 ParameterProcessor
package top.zcwfeng.arouter_compiler;
@AutoService(Processor.class)
@SupportedSourceVersion(SourceVersion.RELEASE_8)
@SupportedAnnotationTypes(ProcessorConfig.PARAMETER_PACKAGE)
public class ParameterProcessor extends AbstractProcessor {
// 操作Element的工具类(类,函数,属性,其实都是Element)
private Elements elementTool;
// type(类信息)的工具类,包含用于操作TypeMirror的工具方法
private Types typeTool;
// Message用来打印 日志相关信息
private Messager messager;
// 文件生成器, 类 资源 等,就是最终要生成的文件 是需要Filer来完成的
private Filer filer;
// 存储所有带@Parameter的属性
private Map<TypeElement, List<Element>> tempParameterMap = new HashMap<>();
@Override
public synchronized void init(ProcessingEnvironment processingEnv) {
super.init(processingEnv);
filer = processingEnv.getFiler();
elementTool = processingEnv.getElementUtils();
messager = processingEnv.getMessager();
typeTool = processingEnv.getTypeUtils();
messager.printMessage(Diagnostic.Kind.NOTE, "APT--->ParameterProcessor init");
}
// TODO: 2020/11/21 生成模板
// 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");
// }
// }
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
// 由于返回了 false 就不需要一下代码了
// if (annotations.isEmpty()) {
// messager.printMessage(Diagnostic.Kind.NOTE, "未发现@Arouter注解的地方");
// return false;
// }
if (!ProcessorUtils.isEmpty(annotations)) {
Set<? extends Element> elements = roundEnv.getElementsAnnotatedWith(Parameter.class);
if (!ProcessorUtils.isEmpty(elements)) {
// 需要一个缓存存储所有带有注释的属性
for (Element element : elements) {
// 字段节点的上一个节点是类,@Parameter 属性的上一个节点。属性的父节点
TypeElement enclosingElement = (TypeElement) element.getEnclosingElement();
// enclosingElement == Personal_MainActivity == key
if (tempParameterMap.containsKey(enclosingElement)) {
tempParameterMap.get(enclosingElement).add(element);
} else {
List<Element> fields = new ArrayList<>();
fields.add(element);
tempParameterMap.put(enclosingElement, fields);
}
}// end for tempParameterMap 缓存有值了
}
// TODO: 2020/11/21 生成类文间 判断是否有需要生成的类文件
if (ProcessorUtils.isEmpty(tempParameterMap)) return true;
TypeElement activityType = elementTool.getTypeElement(ProcessorConfig.ACTIVITY_PACKAGE);
TypeElement parameterType = elementTool.getTypeElement(ProcessorConfig.AROUTER_API_PARAMETER_GET);
ParameterSpec parameterSpec = ParameterSpec.builder(TypeName.OBJECT,
ProcessorConfig.PARAMETER_NAME).build();
//循环遍历缓存
for (Map.Entry<TypeElement, List<Element>> entry : tempParameterMap.entrySet()) {
//key: Personal_MainActivity
//value: [name,sex,age]
TypeElement typeElement = entry.getKey();
// 判断是否是Activity类型的子类
if (!typeTool.isSubtype(typeElement.asType(), activityType.asType())) {
throw new RuntimeException("@Parameter注解仅限与Activity");
}
// Personal_Activity 获取类名
ClassName className = ClassName.get(typeElement);
// 生成方法
ParameterFactory factory = new ParameterFactory.Builder(parameterSpec)
.setClassName(className)
.setMessager(messager)
.build();
//Personal_MainActivity t = (Personal_MainActivity) targetParameter;
factory.addFirstStatement();
for (Element element : entry.getValue()) {
factory.buildStatement(element);
}
// 最终生成的类文件名(类名$$Parameter) 例如:Personal_MainActivity$$Parameter
String finalClassName = typeElement.getSimpleName() + ProcessorConfig.PARAMETER_FILE_NAME;
messager.printMessage(Diagnostic.Kind.NOTE, "APT生成获取参数类文件:" +
className.packageName() + "." + finalClassName);
messager.printMessage(Diagnostic.Kind.NOTE, "APT--->ParameterProcessor process====1111" +parameterType);
try {
JavaFile.builder(className.packageName(),
TypeSpec.classBuilder(finalClassName)
.addSuperinterface(ClassName.get(parameterType))//implements ParameterGet
.addModifiers(Modifier.PUBLIC)
.addMethod(factory.build())
.build()
).build().writeTo(filer);
} catch (IOException e) {
e.printStackTrace();
}
}
}
// true 执行两次 为了防止第二有问题 加了if (set.isEmpty()) { 内部机制回来检测一遍 所以有了第二次
// false 执行一次
return false;
}
}
arouter_api 参数管理器的编写 ParameterManager
public class ParameterManager {
public static ParameterManager instance;
public static ParameterManager getInstance(){
if(instance == null) {
synchronized (ParameterManager.class) {
if (instance == null) {
instance = new ParameterManager();
}
}
}
return instance;
}
// key=类名 value=参数加载的接口
private LruCache<String,ParameterGet> cache;
// 为什么还要拼接,此次拼接 是为了寻找他
static final String FILE_SUFFIX_NAME = "$$Parameter"; // 为了这个效果:Order_MainActivity + $$Parameter
public ParameterManager() {
cache = new LruCache<>(100);
}
/**
* 使用者使用这个方法用来参数接收
* @param activity
*/
public void loadParameter(Activity activity){
String classame = activity.getClass().getName();
ParameterGet parameterLoad = cache.get(classame);
if(null == parameterLoad) {
try {
Class<?> clazz = Class.forName(classame+FILE_SUFFIX_NAME);
parameterLoad = (ParameterGet) clazz.newInstance();
cache.put(classame, parameterLoad);
} catch (Exception e) {
e.printStackTrace();
}
}
parameterLoad.getParameter(activity);
}
}
2.组件化之路由管理器编写。
arouter_api ----RouterManager 编写
public class RouterManager {
private String group; // 路由的组名 app,order,personal ...
private String path; // 路由的路径 例如:/order/Order_MainActivity
/**
* 上面定义的两个成员变量意义:
* 1.拿到ARouter$$Group$$personal 根据组名 拿到 ARouter$$Path$$personal
* 2.操作路径,通过路径 拿到 Personal_MainActivity.class,就可以实现跳转了
*/
// 单例模式
private static RouterManager instance;
public static RouterManager getInstance() {
if (instance == null) {
synchronized (RouterManager.class) {
if (instance == null) {
instance = new RouterManager();
}
}
}
return instance;
}
// 提供性能 LRU缓存
private LruCache<String, ARouterGroup> groupLruCache;
private LruCache<String, ARouterPath> pathLruCache;
// 为了拼接,例如:ARouter$$Group$$personal
private final static String FILE_GROUP_NAME = "ARouter$$Group$$";
private RouterManager() {
groupLruCache = new LruCache<>(100);
pathLruCache = new LruCache<>(100);
}
/***
* @param path 例如:/order/Order_MainActivity
* * @return
*/
public BundleManager build(String path) {
if (TextUtils.isEmpty(path) || !path.startsWith("/")) {
throw new IllegalArgumentException("不按常理出牌 path乱搞的啊,正确写法:如 /order/Order_MainActivity");
}
// 同学可以自己增加
// ...
if (path.lastIndexOf("/") == 0) { // 只写了一个 /
throw new IllegalArgumentException("不按常理出牌 path乱搞的啊,正确写法:如 /order/Order_MainActivity");
}
// 截取组名 /order/Order_MainActivity finalGroup=order
String finalGroup = path.substring(1, path.indexOf("/", 1)); // finalGroup = order
if (TextUtils.isEmpty(finalGroup)) {
throw new IllegalArgumentException("不按常理出牌 path乱搞的啊,正确写法:如 /order/Order_MainActivity");
}
// 证明没有问题,没有抛出异常
this.path = path; // 最终的效果:如 /order/Order_MainActivity
this.group = finalGroup; // 例如:order,personal
// TODO 走到这里后 grooup 和 path 没有任何问题 app,order,personal /app/MainActivity
return new BundleManager(); // Builder设计模式 之前是写里面的, 现在写外面吧
}
public Object navigation(Context context, BundleManager bundleManager) {
.....
return null;
}
arouter_api ---- BundlerManager
public class BundleManager {
// Intent传输 携带的值,保存到这里
private Bundle bundle = new Bundle();
public Bundle getBundle() {
return bundle;
}
// TODO: 2020/11/21 继续增加Bundle 其他扩展类型
// 对外界提供,可以携带参数的方法
public BundleManager withString(@NonNull String key, @Nullable String value) {
bundle.putString(key, value);
return this; // 链式调用效果 模仿开源框架
}
public BundleManager withBoolean(@NonNull String key, @Nullable boolean value) {
bundle.putBoolean(key, value);
return this;
}
public BundleManager withInt(@NonNull String key, @Nullable int value) {
bundle.putInt(key, value);
return this;
}
public BundleManager withDouble(@NonNull String key, @Nullable double value) {
bundle.putDouble(key, value);
return this;
}
public BundleManager withFloat(@NonNull String key, @Nullable float value) {
bundle.putFloat(key, value);
return this;
}
public BundleManager withBundle(Bundle bundle) {
this.bundle = bundle;
return this;
}
// 直接完成跳转
public Object navigation(Context context){
return RouterManager.getInstance().navigation(context, this);
}
}
3.路由navigation。
public Object navigation(Context context, BundleManager bundleManager) {
// 例如:寻找 ARouter$$Group$$personal 寻址 ARouter$$Group$$order ARouter$$Group$$app
String groupClassName = context.getPackageName() + "." + FILE_GROUP_NAME + group;
Log.e("David", "navigation: groupClassName=" + groupClassName);
try {
// TODO 第一步 读取路由组Group类文件
ARouterGroup loadGroup = groupLruCache.get(group);
if (null == loadGroup) { // 缓存里面没有东东
// 加载APT路由组Group类文件 例如:ARouter$$Group$$order
Class<?> aClass = Class.forName(groupClassName);
// 初始化类文件
loadGroup = (ARouterGroup) aClass.newInstance();
// 保存到缓存
groupLruCache.put(group, loadGroup);
}
if (loadGroup.getGroupMap().isEmpty()) {
throw new RuntimeException("路由表Group报废了..."); // Group这个类 加载失败
}
// TODO 第二步 读取路由Path类文件
ARouterPath loadPath = pathLruCache.get(path);
if (null == loadPath) { // 缓存里面没有东东 Path
// 1.invoke loadGroup
// 2.Map<String, Class<? extends ARouterLoadPath>>
Class<? extends ARouterPath> clazz = loadGroup.getGroupMap().get(group);
// 3.从map里面获取 ARouter$$Path$$personal.class
loadPath = clazz.newInstance();
// 保存到缓存
pathLruCache.put(path, loadPath);
}
// TODO 第三步 跳转
if (loadPath != null) { // 健壮
if (loadPath.getPathMap().isEmpty()) { // pathMap.get("key") == null
throw new RuntimeException("路由表Path报废了...");
}
// 最后才执行操作
RouterBean routerBean = loadPath.getPathMap().get(path);
if (routerBean != null) {
switch (routerBean.getTypeEnum()) {
case ACTIVITY:
Intent intent = new Intent(context, routerBean.getMyclass()); // 例如:getClazz == Order_MainActivity.class
intent.putExtras(bundleManager.getBundle()); // 携带参数
context.startActivity(intent, bundleManager.getBundle());
break;
//同学们可以自己扩展 类型
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
测试使用自定义路由跳转
@ARouter(path = "/app/MainActivity")
public class MainActivity extends AppCompatActivity {
@ARouter(path = "/order/Order_MainActivity")
public class Order_MainActivity extends AppCompatActivity {
@ARouter(path = "/personal/Personal_MainActivity")
public class Personal_MainActivity extends AppCompatActivity {
@Parameter
String name;
@Parameter
String sex;
@Parameter
int age;
使用跳转
public void jumpApp(View view) {
// 使用我们自己写的路由 跳转交互
RouterManager.getInstance()
.build("/app/MainActivity")
.withString("name", "杜子腾")
.navigation(this); // 组件和组件通信
}
public void jumpOrder(View view) {
// 使用我们自己写的路由 跳转交互
RouterManager.getInstance()
.build("/order/Order_MainActivity")
.withString("name", "杜子腾")
.navigation(this); // 组件和组件通信
}