0
点赞
收藏
分享

微信扫一扫

JavaPoet APT(三)组件化路由

回顾一下之前的调用逻辑。在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); // 组件和组件通信

    }
举报

相关推荐

27.APT技术与JavaPoet

0 条评论