美文网首页
MRouter(Android路由)

MRouter(Android路由)

作者: 24K男 | 来源:发表于2018-06-27 08:38 被阅读0次

    路由的意义:

    1. 模块间解耦,不能在代码中写死Activity类名。
    2. 动态配置业务需求,现在都是业务模块化开发了。

    1. 注解

    我们这次编写的MRoute主要使用了编译时注解技术,注解在我们日常使用的框架中都有体现。

    运行时注解,主要集合反射来完成功能。

    编译时注解,则主要是在编译阶段生成类,来辅助我们后面实现功能。

    关于注解,不做详细描述。

    2. Activity跳转

    正常情况下,我们进行Activity跳转是这样的:

    Intent intent=new Intent(this,AnotherActivity.class);
    startActivity(intent);
    

    使用路由跳转是这样的:

    
    MRouter.startActivity(context,url,bundle);
    
    

    MRouter会根据传入的参数url来查找对应的类,然后完成Activity的跳转。

    3. 具体实现

    3.1 项目结构

    MRoute
    |--RouteAnnotation
    |
    |--RouteProcessor
    |
    |--RouteApi

    3.2 RouteAnnotation

    注意该Moudule为Java Library.

    RouteAnnotation中定义了MRouter使用的注解Route,具体实现如下:

    /**
     * Android路由注解。
     *
     * @author zhangshuai.
     */
    @Documented
    @Inherited
    @Retention(RetentionPolicy.CLASS)
    @Target(ElementType.TYPE)
    public @interface Route {
        String url() default "";
    }
    

    要点解释:

    1. 因为使用编译时注解,因此Route的只存在于class中,不是Runtime。
    2. 注解的只能使用在类上。

    3.3 RouteCompiler

    该Module同样为Java Library,用于处理注解并生成辅助类。

    该项目中定义了注解处理器RouteProcessor,使用了auto-service、javapoet来辅助完成。

    下面来看核心类RouteProcessor实现:

    
    import core.zs.routeannotation.Route;
    
    @AutoService(Processor.class)
    public class RouteProcessor extends AbstractProcessor {
        
        private Filer mFiler;
    
        @Override
        public synchronized void init(ProcessingEnvironment processingEnv) {
            super.init(processingEnv);
            mFiler = processingEnv.getFiler();
        }
    
        @Override
        public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
            Set<? extends Element> elements = roundEnv.getElementsAnnotatedWith(Route.class);
            TypeSpec spec = processElements(elements);
            try {
                if (spec != null) {
                    // 生成Java文件
                    // RouteMap.java
                    JavaFile.builder("core.zs.route", spec).build().writeTo(mFiler);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            return true;
        }
    
        private TypeSpec processElements(Set<? extends Element> elements) {
            if (elements == null || elements.size() == 0) {
                return null;
            }
    
            // 1. 构造参数,参数为activityMap
            // 参数类型为:HashMap<String,Class<?>>
            ParameterizedTypeName mapTypeName =
                    ParameterizedTypeName.get(ClassName.get(HashMap.class), ClassName.get(String
                            .class), ClassName.get(Class.class));
            ParameterSpec mapSpec = ParameterSpec.builder(mapTypeName, "activityMap").build();
            
            // 2. 构造方法,方法名为initActivityMap
            // 参数为activityMap
            MethodSpec.Builder initMethodBuilder =
                    MethodSpec.methodBuilder("initActivityMap").addModifiers(Modifier.PUBLIC,
                            Modifier.STATIC).addParameter(mapSpec);
            // 3. 处理使用Route注解的类信息
            for (Element element : elements) {
                Route route = element.getAnnotation(Route.class);
                String url = route.url();
                if (null != url && !"".equals(url)) {
                    // 在initActivityMap中添加语句
                    // activityMap.put(url,xxx.class);
                    initMethodBuilder.addStatement("activityMap.put($S,$T.class)", url, ClassName.get
                            ((TypeElement) element));
                }
            }
            // 返回我们构造的类元素
            return TypeSpec.classBuilder("RouteMap").addMethod(initMethodBuilder.build())
                    .addModifiers(Modifier.PUBLIC).build();
        }
    
        @Override
        public Set<String> getSupportedAnnotationTypes() {
            Set<String> set = new LinkedHashSet<>();
            set.add(Route.class.getCanonicalName());
            return set;
        }
    
        @Override
        public SourceVersion getSupportedSourceVersion() {
            return SourceVersion.latestSupported();
        }
    }
    
    
    

    使用处理器后,会在project的app/build/generated/source/apt/debug/项目名 下生产一个RouteMap.java文件。

    其内容如下:

    package core.zs.router;
    
    import java.lang.Class;
    import java.lang.String;
    import java.util.HashMap;
    
    public class RouteMap {
      public static void initActivityMap(HashMap<String, Class> activityMap) {
        activityMap.put("/core/zs/TestActivity",TestActivity.class);
      }
    }
    
    

    3.4 RouteApi

    注意该Module为Android Library,该Module主要是封装一些常用的api,供其他项使用。

    只有一个类MRouter。

    
    package core.zs.routeapi;
    
    /**
     * Created by ZhangShuai on 2018/6/26.
     */
    
    public class MRouter {
    
        public static HashMap<String, Class<?>> activityMap = new HashMap<>();
    
        public static void init(Context context) {
            try {
                // 通过反射来调用RouteMap的initActivityMap方法,将数据保存到activityMap中
                Class clz = Class.forName("core.zs.route.RouteMap");
                if (clz != null) {
                    Method initMapMethod = clz.getMethod("initActivityMap", HashMap.class);
                    initMapMethod.invoke(null, activityMap);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
    
        }
    
        // 替换常规的startActivity方法
        public static void startActivity(Context context, String url, Bundle bundle) {
            if (context == null || url == null) {
                return;
            }
            Class atClazz = activityMap.get(url);
            if (atClazz != null) {
                System.out.println(atClazz.getCanonicalName());
                Intent intent = new Intent(context, atClazz);
                if (bundle != null) {
                    intent.putExtras(bundle);
                }
                context.startActivity(intent);
            }else{
                System.out.println("=====Activity is null.");
            }
    
    
        }
    }
    
    

    3.5 如何使用

    1. 在Application中初始化
    public class MyApp extends Application {
        @Override
        public void onCreate() {
            super.onCreate();
            MRouter.init(this);
        }
    }
    
    1. 在Activity上使用Route注解。
    @Route(url = "/core/zs/route/RouteActivity")
    public class RouteActivity extends AppCompatActivity{
        //....
    }
    
    
    1. 进行跳转
    MRouter.startActivity(MainActivity.this, "/core/zs/route/RouteActivity", null);
    

    4. 总结

    随着项目的不断变化,模块化开发、组件化开发逐步被引入,使用MRouter能很好的帮你实现业务之间的解耦,实现业务之间的简单配置、顺利跳转。

    奉上源码地址MRouter

    相关文章

      网友评论

          本文标题:MRouter(Android路由)

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