美文网首页Android开发Android技术知识Android开发
Android组件化专题-路由动态注入跳转参数以及获取其他模块的

Android组件化专题-路由动态注入跳转参数以及获取其他模块的

作者: 289346a467da | 来源:发表于2018-07-16 22:06 被阅读229次

    上几篇组件化专题文章,我们对路由框架基本实现了,Activity之间当跳转和模块间当通信。

    现在思考一个问题:
    不管是在Activity或者Fragment,跳转都会传递一些参数,然后在对应对Activity或着Fragment获取对应对参数,都要写大量重复的代码,然而我们作为一名有素质有梦想的码农,我们是不可以做这种搬砖的操作的,不想当大牛当码农不是好码农。

    那么我们如何用优雅的代码,解决这个问题呢?请看下面分解

    路由动态注入跳转参数

    原生的获取intent跳转传递过来的参数:

    Intent intent = getIntent();
    final String path = intent.getStringExtra("path");
    ......
    

    同时还有fragment的参数传递等。

    如果稍微进行一些封装的话可以这样写:

    public class MainActivityExtra {
        public static void loadExtra(Main2Activity main2Activity) {
            Intent intent = main2Activity.getIntent();
    
            main2Activity.path = intent.getStringExtra("path");
            
            ......
    
        }
    }
    
    

    上述不管哪种写法,都是相当麻烦和大量的重复代码。

    最为一名有梦想的码农,我理想中的写法:

    在相应的Activity,通过一个注解就可以拿到跳转传递过来的参数的值,然后直接使用。

    @Extra
    public String path;
    

    那么我们如何实现呢? 其实很简单,我们通过注解拿到父类Activity,然后注解变量的类型和名称,然后我们动态生成一个类,通过原生的方式来实现参数获取。

    其实跟上几篇的文章是一样的原理,这里就不再多复述了这是链接组件化专题

    下面就直接一堆代码,抛给你

    1. 首先声明注解
    @Target(ElementType.FIELD)
    @Retention(RetentionPolicy.CLASS)
    public @interface Extra {
        String name() default "";
    }
    
    1. 注解处理器处理注解,这里面的逻辑其实非常简单,主要是看你对APT使用是不是熟练
    @AutoService(Processor.class)
    @SupportedSourceVersion(SourceVersion.RELEASE_7)
    @SupportedAnnotationTypes({Consts.EXTRA_NAME})
    @SupportedOptions({Consts.ARGUMENTS_NAME})
    public class ExtraProcessor extends AbstractProcessor {
    
        /**
         * key:类节点 value:需要注入的属性节点集合
         */
        private Map<TypeElement, List<Element>> extraMap = new HashMap<>();
    
        private Elements elementUtils;
    
        private Types typeUtils;
    
        private Filer filer;
    
        private Log log;
    
        private Messager messager;
    
        @Override
        public synchronized void init(ProcessingEnvironment processingEnvironment) {
            super.init(processingEnvironment);
            elementUtils = processingEnvironment.getElementUtils();
            typeUtils = processingEnvironment.getTypeUtils();
            filer = processingEnvironment.getFiler();
            messager = processingEnvironment.getMessager();
            log = Log.newLog(messager);
        }
    
        @Override
        public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
            if (null != set && !set.isEmpty()) {//注意这里必须要判断set.isEmpty()  否则会走两遍
                log.i("process");
                //拿到注有Extra 的节点集合
                Set<? extends Element> elementsAnnotatedWith = roundEnvironment.getElementsAnnotatedWith(Extra.class);
                if (null != elementsAnnotatedWith) {
                    try {
                        saveExtras(elementsAnnotatedWith);
                        generateExtras();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
                return true;
            }
            return false;
        }
    
        /**
         * 保存节点的信息
         *
         * @param elementsAnnotatedWith
         */
        private void saveExtras(Set<? extends Element> elementsAnnotatedWith) {
            for (Element element : elementsAnnotatedWith) {
                //获取注解父类的节点类型
                TypeElement enclosingElement = (TypeElement) element.getEnclosingElement();
                if (extraMap.containsKey(enclosingElement)) {
                    extraMap.get(enclosingElement).add(element);
                } else {
                    List<Element> list = new ArrayList<>();
                    list.add(element);
                    extraMap.put(enclosingElement, list);
                }
            }
        }
    
        private MethodSpec.Builder builder;
    
        private TypeMirror parcelableType;
    
        private TypeMirror iServiceType;
    
        private TypeElement extraElement;
    
        private TypeMirror activity;
    
        /**
         * 生成表
         */
        private void generateExtras() {
            //支持Activity和Fragment
            activity = elementUtils.getTypeElement(Consts.Activity).asType();
    
            extraElement = elementUtils.getTypeElement(Consts.Extra);
    
            parcelableType = elementUtils.getTypeElement(Consts.PARCELABLE).asType();
    
            iServiceType = elementUtils.getTypeElement(Consts.Service).asType();
    
            log.i("generateExtras");
    
            //参数
            ParameterSpec target = ParameterSpec.builder(TypeName.OBJECT, "target").build();
            if (!Utils.isEmpty(extraMap)) {
                //遍历被Extra注解属性的类
                for (Map.Entry<TypeElement, List<Element>> entry : extraMap.entrySet()) {
    
                    TypeElement classType = entry.getKey();
    
                    log.i("isSubtype:" + typeUtils.isSubtype(classType.asType(), activity) + " | " + classType.asType());
                    if (typeUtils.isSubtype(classType.asType(), activity)) {
                        generateClass(target, entry, classType);
                    } else {
                        throw new RuntimeException("[Just Support Activity Field] : " + classType + " --> " + typeUtils.isSubtype(classType.asType(), activity));
                    }
    
    
                }
            }
        }
    
        public void generateClass(ParameterSpec target, Map.Entry<TypeElement, List<Element>> entry, TypeElement classType) {
    
            builder = MethodSpec.methodBuilder(Consts.EXTRA_METHOD_NAME)//方法名
                    .addAnnotation(Override.class)//注解
                    .addModifiers(Modifier.PUBLIC)//作用域
                    .addParameter(target);//添加参数
            log.i("generate method");
            //设置函数体
            addFuncationBody(entry, classType);
    
            log.i("generate type");
            //生成Java类
            TypeSpec typeSpec = TypeSpec.classBuilder(classType.getSimpleName() + "$$Extra")
                    .addSuperinterface(ClassName.get(extraElement))
                    .addModifiers(Modifier.PUBLIC)
                    .addMethod(builder.build())
                    .build();
            try {
                //生成Java类文件
                log.i("package name:" + ClassName.get(classType).packageName());
                JavaFile.builder(ClassName.get(classType).packageName(), typeSpec).build().writeTo(filer);
            } catch (IOException e) {
                e.printStackTrace();
                log.i("package name error");
            }
        }
    
        private void addFuncationBody(Map.Entry<TypeElement, List<Element>> entry, TypeElement classType) {
            for (Element element : entry.getValue()) {
                //$T t = ($T)target
                builder.addStatement("$T t = ($T)target", classType, classType);
                //遍历注解节点 生成函数体
                TypeMirror typeMirror = element.asType();//获取注解节点的类型
                //获取TypeKind 枚举类型的序列号
                int type = typeMirror.getKind().ordinal();
                //获取属性名
                String fieldName = element.getSimpleName().toString();
                //获取注解的值
                String extraName = element.getAnnotation(Extra.class).name();
                //判断直接的值为空的情况下的处理
                extraName = Utils.isEmpty(extraName) ? fieldName : extraName;
                String defaultValue = "t." + fieldName;
                String statement = defaultValue + " = t.getIntent().";
                if (type == TypeKind.BOOLEAN.ordinal()) {
                    statement += "getBooleanExtra($S, " + defaultValue + ")";
                } else if (type == TypeKind.BYTE.ordinal()) {
                    statement += "getByteExtra($S, " + defaultValue + ")";
                } else if (type == TypeKind.SHORT.ordinal()) {
                    statement += "getShortExtra($S, " + defaultValue + ")";
                } else if (type == TypeKind.INT.ordinal()) {
                    statement += "getIntExtra($S, " + defaultValue + ")";
                } else if (type == TypeKind.LONG.ordinal()) {
                    statement += "getLongExtra($S, " + defaultValue + ")";
                } else if (type == TypeKind.CHAR.ordinal()) {
                    statement += "getCharExtra($S, " + defaultValue + ")";
                } else if (type == TypeKind.FLOAT.ordinal()) {
                    statement += "getFloatExtra($S, " + defaultValue + ")";
                } else if (type == TypeKind.DOUBLE.ordinal()) {
                    statement += "getDoubleExtra($S, " + defaultValue + ")";
                } else {
                    //数组类型
                    if (type == TypeKind.ARRAY.ordinal()) {
                        addArrayStatement(statement, fieldName, extraName, typeMirror, element);
                    } else {
                        //Object
                        addObjectStatement(statement, fieldName, extraName, typeMirror, element);
                    }
                    return;
                }
                log.i("generate statement:" + statement);
                builder.addStatement(statement, extraName);
            }
        }
    
        /**
         * 添加对象 String/List/Parcelable
         *
         * @param statement
         * @param extraName
         * @param typeMirror
         * @param element
         */
        private void addObjectStatement(String statement, String fieldName, String extraName,
                                        TypeMirror typeMirror,
                                        Element element) {
            //Parcelable
            if (typeUtils.isSubtype(typeMirror, parcelableType)) {
                statement += "getParcelableExtra($S)";
            } else if (typeMirror.toString().equals(Consts.STRING)) {
                statement += "getStringExtra($S)";
            } else if (typeUtils.isSubtype(typeMirror, iServiceType)) {
    //            TestService testService = (TestService) DNRouter.getInstance().build("/main/service1")
    //                    .navigation();
    //            testService.test();
                statement = "t." + fieldName + " = ($T) $T.getInstance().build($S).navigation()";
                builder.addStatement(statement, TypeName.get(element.asType()), Consts.ROUTER,
                        extraName);
                return;
            } else {
                //List
                TypeName typeName = ClassName.get(typeMirror);
                //泛型
                if (typeName instanceof ParameterizedTypeName) {
                    //list 或 arraylist
                    ClassName rawType = ((ParameterizedTypeName) typeName).rawType;
                    //泛型类型
                    List<TypeName> typeArguments = ((ParameterizedTypeName) typeName)
                            .typeArguments;
                    if (!rawType.toString().equals(Consts.ARRAYLIST) && !rawType.toString()
                            .equals(Consts.LIST)) {
                        throw new RuntimeException("Not Support Inject Type:" + typeMirror + " " +
                                element);
                    }
                    if (typeArguments.isEmpty() || typeArguments.size() != 1) {
                        throw new RuntimeException("List Must Specify Generic Type:" + typeArguments);
                    }
                    TypeName typeArgumentName = typeArguments.get(0);
                    TypeElement typeElement = elementUtils.getTypeElement(typeArgumentName
                            .toString());
                    // Parcelable 类型
                    if (typeUtils.isSubtype(typeElement.asType(), parcelableType)) {
                        statement += "getParcelableArrayListExtra($S)";
                    } else if (typeElement.asType().toString().equals(Consts.STRING)) {
                        statement += "getStringArrayListExtra($S)";
                    } else if (typeElement.asType().toString().equals(Consts.INTEGER)) {
                        statement += "getIntegerArrayListExtra($S)";
                    } else {
                        throw new RuntimeException("Not Support Generic Type : " + typeMirror + " " +
                                element);
                    }
                } else {
                    throw new RuntimeException("Not Support Extra Type : " + typeMirror + " " +
                            element);
                }
            }
            builder.addStatement(statement, extraName);
        }
    
        /**
         * 添加数组
         *
         * @param statement
         * @param fieldName
         * @param typeMirror
         * @param element
         */
        private void addArrayStatement(String statement, String fieldName, String extraName, TypeMirror
                typeMirror, Element element) {
            //数组
            switch (typeMirror.toString()) {
                case Consts.BOOLEANARRAY:
                    statement += "getBooleanArrayExtra($S)";
                    break;
                case Consts.INTARRAY:
                    statement += "getIntArrayExtra($S)";
                    break;
                case Consts.SHORTARRAY:
                    statement += "getShortArrayExtra($S)";
                    break;
                case Consts.FLOATARRAY:
                    statement += "getFloatArrayExtra($S)";
                    break;
                case Consts.DOUBLEARRAY:
                    statement += "getDoubleArrayExtra($S)";
                    break;
                case Consts.BYTEARRAY:
                    statement += "getByteArrayExtra($S)";
                    break;
                case Consts.CHARARRAY:
                    statement += "getCharArrayExtra($S)";
                    break;
                case Consts.LONGARRAY:
                    statement += "getLongArrayExtra($S)";
                    break;
                case Consts.STRINGARRAY:
                    statement += "getStringArrayExtra($S)";
                    break;
                default:
                    //Parcelable 数组
                    String defaultValue = "t." + fieldName;
                    //object数组 componentType获得object类型
                    ArrayTypeName arrayTypeName = (ArrayTypeName) ClassName.get(typeMirror);
                    TypeElement typeElement = elementUtils.getTypeElement(arrayTypeName
                            .componentType.toString());
                    //是否为 Parcelable 类型
                    if (!typeUtils.isSubtype(typeElement.asType(), parcelableType)) {
                        throw new RuntimeException("Not Support Extra Type:" + typeMirror + " " +
                                element);
                    }
                    statement = "$T[] " + fieldName + " = t.getIntent()" +
                            ".getParcelableArrayExtra" +
                            "($S)";
                    builder.addStatement(statement, parcelableType, extraName);
                    builder.beginControlFlow("if( null != $L)", fieldName);
                    statement = defaultValue + " = new $T[" + fieldName + ".length]";
                    builder.addStatement(statement, arrayTypeName.componentType)
                            .beginControlFlow("for (int i = 0; i < " + fieldName + "" +
                                    ".length; " +
                                    "i++)")
                            .addStatement(defaultValue + "[i] = ($T)" + fieldName + "[i]",
                                    arrayTypeName.componentType)
                            .endControlFlow();
                    builder.endControlFlow();
                    return;
            }
            builder.addStatement(statement, extraName);
        }
    }
    
    

    其实上面的注解处理器,会动态生成这样的一个类

    public class Main2Activity$$Extra implements IExtra {
      @Override
      public void loadExtra(Object target) {
        Main2Activity t = (Main2Activity)target;
        t.path = t.getIntent().getStringExtra("path");
      }
    }
    
    1. 通过一个API去加载这个类
     public void loadExtra(Activity activity) {
            String name = activity.getClass().getName();
            IExtra iExtra = extraLruCache.get(name);
            try {
                if (iExtra == null) {
                    iExtra = (IExtra) Class.forName(activity.getClass().getName() + "$$Extra").getConstructor().newInstance();
                }
                iExtra.loadExtra(activity);
                extraLruCache.put(name, iExtra);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
    1. 具体的调用实现
    public class ModuleTest2Activity extends AppCompatActivity {
    
        @Extra(name = "path")
        public String url;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_module_test2);
            PrimRouter.getInstance().inject(this);
           
            TextView module2_textView = findViewById(R.id.module2_textView);
    //        Intent intent = getIntent();
    //        final String path = intent.getStringExtra("path");
            module2_textView.setText("我是module2,我的地址是:/module2/test. 我是被地址:" + url + " 调起的");
         }
    }
    

    这样处理不仅大大提高了编码效率还减少了大量重复的代码,也提高了程序的可读性.

    实现fragment的跳转

    这里我们需要在原来的基础上,加几句代码。代码地址

    //拿到fragment的全类名
    TypeElement fragment = elementUtils.getTypeElement(Consts.Fragment);
    
            TypeElement v4Fragment = elementUtils.getTypeElement(Consts.V4Fragment);
    
            //单个的节点
            for (Element element : annotatedWith) {
                // 获取类信息 如Activity类
                TypeMirror typeMirror = element.asType();
                // 获取节点的注解信息
                Router annotation = element.getAnnotation(Router.class);
                log.i(typeMirror + " | " + activity.asType());
                //只能指定的类上面使用
                if (typeUtils.isSubtype(typeMirror, activity.asType())) {
                    //存储路由相关的信息
                    routerMeta = new RouterMeta(RouterMeta.Type.ACTIVITY, annotation, element);
                } else if (typeUtils.isSubtype(typeMirror, service.asType())) {
                    //存储路由相关的信息
                    routerMeta = new RouterMeta(RouterMeta.Type.SERVICE, annotation, element);
                } else if (typeUtils.isSubtype(typeMirror, fragment.asType()) || typeUtils.isSubtype(typeMirror, v4Fragment.asType())) {
                    //存储路由相关的信息
                    routerMeta = new RouterMeta(RouterMeta.Type.FRAGMENT, annotation, element);
                } else {
                    throw new RuntimeException("Just Support Activity Router!");
                }
    
                //检查是否配置group如果没有配置 则从path中截取组名
                checkRouterGroup(routerMeta);
            }
    

    然后在我们的API库,返回fragment

    case FRAGMENT:
                    Class<?> fragment = jumpCard.getDestination();
                    try {
                        Object instance = fragment.getConstructor().newInstance();
                        if (instance instanceof Fragment) {
                            ((Fragment) instance).setArguments(jumpCard.getExtras());
                        } else if (instance instanceof android.support.v4.app.Fragment) {
                            ((android.support.v4.app.Fragment) instance).setArguments(jumpCard.getExtras());
                        }
                        return instance;
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
    

    实现效果如下:

    image.png

    到此为止,我们的路由框架实现了以下功能:
    支持直接解析标准URL路由地址进行跳转,并自动注入参数到目标页面中
    支持多模块工程使用
    支持模块间的通信
    支持获取其他模块的fragment

    Android的组件化专题:
    组件化配置

    APT实战

    路由框架原理

    模块间的业务通信

    相关文章

      网友评论

      本文标题:Android组件化专题-路由动态注入跳转参数以及获取其他模块的

      本文链接:https://www.haomeiwen.com/subject/mijipftx.html