美文网首页
简单路由跳转

简单路由跳转

作者: ReleaseYH | 来源:发表于2018-06-27 09:59 被阅读0次

当应用模块过多,各个模块可能会需要其他模块的跳转处理。
模块间解耦,不需要再类中明确跳转目标的类名
动态配置,业务需求原因,部分诸如banner页等地方的地址需要动态可配的,这个时候就不方便写死类名,路由是一个比较好的解决方式。

普通跳转

//正常情况下Activity之间的跳转如下
Intent intent=new Intent(this,TestActivity.class);
startActivity(intent);

而路由跳转的原理实际上执行的也是类似的代码,只不过路由执行的是注解生成的逻辑代码。项目下所有注解的Activity会以Map的形式保存下来,类似于下面这样的逻辑.

 public static void initActivityMap(HashMap<String, Class> activityMap) {
    activityMap.put("test1", TestActivity1.class);
    activityMap.put("test2", TestActivity2.class);
}

之后在传入test1这样的字符串,通过遍历map找到对应的TestActivity1这样的目标Activity。最后执行startActivity()实现跳转,上述就是一个简单的路由的跳转。

具体实现
在工程下建立如下几个module

  --app                   (主工程)
  --route_annotation      (java module 自定义注解)
  --route-api             (Android module)
  --route_compiler        (java module 注解处理器逻辑)

route_annotation 定义注解

// 一个注解接口

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.CLASS)
public @interface Route {
    String [] value();
}

route_compiler 注解处理器逻辑

新建一个注解处理器的类RouteProcessor 继承自AbstractProcessor
具体实现

@AutoService(Processor.class)
 public class RouteProcessor extends AbstractProcessor {

private Messager mMessager;
private Filer mFiler;

@Override
public synchronized void init(ProcessingEnvironment processingEnvironment) {
    super.init(processingEnvironment);
    mMessager = processingEnv.getMessager();
    mFiler = processingEnv.getFiler();
}

@Override
public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
    Set<? extends Element> routeElements = roundEnvironment.getElementsAnnotatedWith(Route.class);
    try {
        TypeSpec typeSpec = processRouterTable(routeElements);
        if (typeSpec != null) {
            JavaFile.builder("com.dly.routeDemo", typeSpec).build().writeTo(mFiler);
        }
    } catch (Exception e) {
        e.printStackTrace();
        error(e.getMessage());
    }
    return true;
}

private TypeSpec processRouterTable(Set<? extends Element> elements) {
    //注意这里一定要做判空处理,因为apt会多次扫描项目所有文件包括javaPoet生成的文件.
    //不做这步处理的话,第一次生成你需要的文件,第二次再进行扫描的时候,又会去生成文件,那时系统就会报一个异常,提示不能生成相同的文件
    if (elements == null || elements.size() == 0) {
        return null;
    }
    ParameterizedTypeName mapTypeName = ParameterizedTypeName
            .get(ClassName.get(HashMap.class), ClassName.get(String.class),
                    ClassName.get(Class.class));
    ParameterSpec mapParameterSpec = ParameterSpec.builder(mapTypeName, "activityMap")
            .build();
    MethodSpec.Builder routerInitBuilder = MethodSpec.methodBuilder("initActivityMap")
            .addModifiers(Modifier.PUBLIC, Modifier.STATIC)
            .addParameter(mapParameterSpec);

    for (Element element : elements) {
        Route route = element.getAnnotation(Route.class);
        String[] routerUrls = route.value();
        for (String url : routerUrls) {
            //核心逻辑  将字符与类做映射关联
            routerInitBuilder.addStatement("activityMap.put($S, $T.class)", url, ClassName.get((TypeElement) element));
        }
    }

    return TypeSpec.classBuilder("AutoCreateModuleActivityMap_app")
            .addModifiers(Modifier.PUBLIC)
            .addMethod(routerInitBuilder.build())
            .build();
}


@Override
public Set<String> getSupportedAnnotationTypes() {
    Set<String> ret = new HashSet<>();
    ret.add(Route.class.getCanonicalName());
    return ret;
}

@Override
public SourceVersion getSupportedSourceVersion() {
    return SourceVersion.latestSupported();
}

private void error(String error) {
    mMessager.printMessage(Diagnostic.Kind.ERROR, error);
}

}

上述RouteProcessor类会在AS编译完成之后,会在目录app/build/generated/source/apt/debug/项目名 下生产一个java文件。

public class AutoCreateModuleActivityMap_app {
    public static void initActivityMap(HashMap<String, Class> activityMap) {
      activityMap.put("test1", TestActivity1.class);
      activityMap.put("test2", TestActivity2.class);
  }
}

}
这个java文件会保存你注解过的类以及对于字符串之间的映射关系。

route_api 需要执行具体的跳转逻辑 即我们熟悉的startActivity

新建Route.class

public class Route {

    private static HashMap<String, Class> activityMap = new HashMap<>();
    private static Application mApplication;

    public static void init(Application application) {
        mApplication = application;
        try {
            //通过反射调用AutoCreateModuleActivityMap_app类的方法,并给activityMap赋值
            Class clazz = Class.forName("com.dly.routeDemo.AutoCreateModuleActivityMap_app");
            Method method = clazz.getMethod("initActivityMap", HashMap.class);
            method.invoke(null, activityMap);
            for (String key : activityMap.keySet()) {
                System.out.println("activityMap = " + activityMap.get(key));
            }

        } catch (Exception e) {
            e.printStackTrace();
       }
    }

    public static void open(String url) {
        for (String key : activityMap.keySet()) {
            if (url.equals(key)) {
                Intent intent = new Intent(mApplication, activityMap.get(key));
                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK );
                mApplication.startActivity(intent);
            }
        }
    }

}

一个简单的反射调用给我们自己定义的ActivityMap赋值.这样的话我们就拥有了ActivityMap的集合了。

app 主工程

定义一个TestApplication用来初始化路由

public class TestApplication extends Application {
    @Override
   public void onCreate() {
        super.onCreate();
        Route.init(this);
    }
}

然后MainActivity下执行路由跳转即可。

    public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

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

    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.text1:
                Route.open("test1");
                break;
            case R.id.text2:
                Route.open("test2");
                break;
        }
    }
}

对应的TestActivity1类。

@Route("test1")
    public class TestActivity1 extends AppCompatActivity {

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_test);
    }
}

上述几个流程就完成了一个最为简单的路由跳转。

相关文章

  • Flutter GetX基础教程(五):Navigation路由

    使用GetX 进行路由跳转非常的简单,只需要调用Get.to()即可进行路由跳转,而系统的路由跳转需要写八行代码,...

  • 简单路由跳转

    当应用模块过多,各个模块可能会需要其他模块的跳转处理。模块间解耦,不需要再类中明确跳转目标的类名动态配置,业务需求...

  • 路由跳转(非命名路由)

    单纯跳转: 路由传值跳转: 路由传值返回跳转:

  • Android路由框架Router分析

    Android路由框架Router 什么是路由?说简单点就是映射页面跳转关系的,当然它也包含跳转相关的一切功能。 ...

  • Vue 动态设置路由Meta title 名称

    路由配置 路由跳转 或路由配置 路由跳转 都可以,看着用。随堂笔记防遗忘!

  • router原理

    什么是路由 router(路由)是一种处理访问先后关系的机制,简单说就是允许我们再不同页面中跳转,记录跳转关系还能...

  • flutter笔记一

    路由跳转 创建新路由

  • Vue路由的单页面应用

    VueJs路由的简单单页面应用: 1.路由的认识:传统的页面跳转是用超链接a来实现的,路由功能与它类似。路由将路径...

  • 路由跳转的总结

    路由跳转 方式1返回上一级或指定的路由 方式2使用路由跳转

  • angualr(二) 路由之angualr-router

    创建项目 路由的基本使用 路由对象图示 路由基本配置 路由通配符配置 HTML里面跳转链接 在js里面跳转路由 路...

网友评论

      本文标题:简单路由跳转

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