Router解决跨模块下的页面跳转示例

网友投稿 401 2023-02-27


Router解决跨模块下的页面跳转示例

一、前言

开始模块化开发项目之后,一个很重要的问题就是页面见的跳转问题。

关于模块化发开,可详见我的另一片文章 android模块化开发探索 。

正是由于将项目模块化拆分,各模块之间没有任何依赖关系,也互相不可见,那么从A模块的a界面跳转到B模块的b界面该怎么办呢?

二、跨模块跳转的方法

这里我们会先介绍这几种常见的跳转方法:

显示跳转

隐示跳转

Scheme协议跳转

Router路由表方案

2.1 显示跳转

显示跳转即我们最最常用的跳转方法:使用Intent,传入当前Activity上下文,和目标Activity的class对象即可,如下:

Intent intent = new Intent();

intent.setClass(mContext, GuideActivity.class);

startActivity(intent);

显然,这种方法只能是目标Activity可见(Activity在同一个Module下)的时候才可以这样调用。不适合跨模块间的跳转。

2.2 隐示跳转

我们这里说的隐示跳转,intent不设置class,而是设置Action或者Category。

例如:

在清单文件中

android:name="com.whaty.base.BaseWebViewActivity"

android:hardwareAccelerated="true">

android:name="com.whaty.base.BaseWebViewActivity"

android:hardwareAccelerated="true">

跳转时:

//创建一个隐式的 Intent 对象:Action 动作

Intent intent = new Intent();

//设置 Intent 的动作为清单中指定的action

intent.setAction("com.whaty.base.BaseWebViewActivity");

startActivity(intent);

2.3 scheme跳转

如果我们为 B 页面定义一个 URI - wsc://home/bbb,然后把共享的 messageModel 拍平序列化成 json 串,那么 A 只需要拼装一个符合 B 页面 scheme 的跳转协议就可以了。 wsc://home/bbb?message={ “name”:”John”, “age”:31, “city”:”New York” }

在清单文件中,配置data属性,设置其host、path、scheme等

android:host="bbb"

android:path="/home"

android:scheme="wsc" />

android:host="bbb"

android:path="/home"

android:scheme="wsc" />

android:host="bbb"

android:path="/home"

android:scheme="wsc" />

跳转时:

final Uri uri = new Uri.Builder().authority("wsc").path("home/bbb").appendQueryParameter("message", new Gson().toJson(messageModel)).build();

final Intent intent = new Intent(Intent.ACTION_VIEW);

intent.setData(uri);

startActivity(intent);

以上的方法,都不是我们想要的,接下来开始介绍我们的Router方案。

三、为什么要用Router

Google提供了显式和隐式两种原生路由方案。但在模块化开发中,显式Intent存在类直接依赖的问题,造成模块间严重耦合。隐式Intent则需要在Manifest中配置大量路径,导致难以拓展(如进行跳转拦截)。为了解决以上问题,我们需要采用一套更为灵活的Router方案。

四、实现思路

思路是这样的:

使用注解,为每个目标Activity标注别名。在应用启动时,对所有类进行扫名,将注解过的Activity存于路由表中。

跳转时,在路由表中通过别名获取目标Activity的class对象,使用Intent实现跳转。

五、代码实现

5.1 自定义注解

/**

* Description: 路由跳转界面 注解

* Created by jia on 2018/1/10.

* 人之所以能,是相信能

*/

@Target(ElementType.TYPE) //注解作用于类型(类,接口,注解,枚举)

@Retention(RetentionPolicy.RUNTIME) //运行时保留,运行中可以处理

@Documented // 生成javadoc文件

public @interface Action {

String DEFAULT = "js";

String value() default DEFAULT;

}

关于自定义注解的详细介绍,请阅读我的文章java进阶之自定义注解。这里不再多说。

5.2 注解Activity

@Action("MainActivity")

public class MainActivity extends BaseActivity implements TabLayout.OnTabSelectedListener {

...

}

在创建Activity时,用刚刚自定义的注解进行注解,为其注释别名。

5.3 启动时扫描

private void getAllActivities(Context ctx){

try {

//通过资源路径获得DexFile

DexFile e = new DexFile(ctx.getPackageResourcePath());

Enumeration entries = e.entries();

//遍历所有元素

while(entries.hasMoreElements()) {

String entryName = (String)entries.nextElement();

//匹配Activity包名与类名

if(entryNhttp://ame.contains("activity") && entryName.contains("Activity")) {

//通过反射获得Activity类

Class entryClass = Class.forName(entryName);

if(entryClass.isAnnotationPresent(Action.class)) {

Action action = (Action)entryClass.getAnnotation(Action.class);

this.map.put(action.value(), entryClass);

}http://

}

}

} catch (Exception e) {

e.printStackTrace();

}

}

在应用启动时,Application中对包下的所有类进行扫描,先找到名字中到activity的(定义到activity包下),并将带有注解标注的Activity,存入map中。

5.4 跳转

/**

* 页面跳转

* @param activity

* @param alias

*/

public void jumpActivity(Activity activity, String alias) throws ClassNotFoundException{

if(map.containsKey(alias)) {

Intent intent = new Intent(activity, map.get(alias));

activity.startActivity(intent);

} else {

throw new ClassNotFoundException();

}

}

跳转的时候传入目标Activity的别名即可(这里的别名就是注解的别名)。

总结

通过这种方式,解决了跳转Activity所产生的的模块依赖问题,相较于原生方案,拓展性更强。但这种方案只是阶段性的,还存在一些问题。首先,加载过程中,频繁使用到反射,会产生性能问题。其次,对于每个Activity的别名,需要进行统一维护,增加了协作成本。还有待优化。

当然,市面上有很多KcfVHG流行的Router方案(如阿里的ARouter),这里只是介绍了一个思路,有好的建议欢迎交流,一起进步。


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:接口api文档结构(api接口的简单编写方式)
下一篇:ScheduledExecutorService任务定时代码示例
相关文章

 发表评论

暂时没有评论,来抢沙发吧~