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


Posted in Javascript onJanuary 11, 2018

一、前言

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

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

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

二、跨模块跳转的方法

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

  1. 显示跳转
  2. 隐示跳转
  3. Scheme协议跳转
  4. 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。

例如:

在清单文件中

<!--网页展示界面-->
<activity
  android:name="com.whaty.base.BaseWebViewActivity"
  android:hardwareAccelerated="true">
    <intent-filter>
      <category android:name="android.intent.category.DEFAULT" />
      <action android:name="com.whaty.base.BaseWebViewActivity" />
    </intent-filter>
</activity>

跳转时:

//创建一个隐式的 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等

<activity android:name=".ui.BbbActivity"
  <intent-filter>
    <category android:name="android.intent.category.DEFAULT" />
    <action android:name="android.intent.action.VIEW" />
    <data
      android:host="bbb"
      android:path="/home"
      android:scheme="wsc" />
  </intent-filter>
</activity>

跳转时:

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实现跳转。

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

五、代码实现

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(entryName.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);
        }
      }
    }
  } 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的别名,需要进行统一维护,增加了协作成本。还有待优化。

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

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
niceTitle 基于jquery的超链接提示插件
May 31 Javascript
JS图片根据鼠标滚动延时加载的实例代码
Jul 13 Javascript
JQuery插件fancybox无法在弹出层使用左右键的解决办法
Dec 25 Javascript
优化javascript的执行效率一些方法总结
Dec 25 Javascript
JQuery对表格进行操作的常用技巧总结
Apr 23 Javascript
jQuery中:checkbox选择器用法实例
Jan 03 Javascript
全面解析JavaScript的Backbone.js框架中的Router路由
May 05 Javascript
在vue中,v-for的索引index在html中的使用方法
Mar 06 Javascript
vue 中动态绑定class 和 style的方法代码详解
Jun 01 Javascript
详解html-webpack-plugin插件(用法总结)
Sep 12 Javascript
node后端服务保活的实现
Nov 10 Javascript
vue下拉刷新组件的开发及slot的使用详解
Dec 23 Vue.js
vuex 使用文档小结篇
Jan 11 #Javascript
js判断传入时间和当前时间大小实例(超简单)
Jan 11 #Javascript
js点击时关闭该范围下拉菜单之外的菜单方法
Jan 11 #Javascript
纯js代码生成可搜索选择下拉列表的实例
Jan 11 #Javascript
web前端vue之vuex单独一文件使用方式实例详解
Jan 11 #Javascript
vue-cli webpack 引入jquery的方法
Jan 10 #jQuery
JS计算两个时间相差分钟数的方法示例
Jan 10 #Javascript
You might like
PHP中的gzcompress、gzdeflate、gzencode函数详解
2014/07/29 PHP
PHP的Yii框架中Model模型的学习教程
2016/03/29 PHP
javascript页面加载完执行事件代码
2014/02/11 Javascript
document.addEventListener使用介绍
2014/03/07 Javascript
JavaScript使用setTimeout实现延迟弹出警告框的方法
2015/04/07 Javascript
JS实现两表格里数据来回转移的方法
2015/05/28 Javascript
javascript 常见功能汇总
2015/06/11 Javascript
在Python中使用glob模块查找文件路径的方法
2015/06/17 Javascript
Sort()函数的多种用法
2016/03/20 Javascript
【经验总结】编写JavaScript代码时应遵循的14条规律
2016/06/20 Javascript
使用vue.js2.0 + ElementUI开发后台管理系统详细教程(一)
2017/01/21 Javascript
JavaScript中递归实现的方法及其区别
2017/09/12 Javascript
jQuery实现的监听导航滚动置顶状态功能示例
2018/07/23 jQuery
微信小程序自定义组件封装及父子间组件传值的方法
2018/08/28 Javascript
webpack3里使用uglifyjs压缩js时打包报错的解决
2018/12/13 Javascript
vue无限轮播插件代码实例
2019/05/10 Javascript
Vue CLI项目 axios模块前后端交互的使用(类似ajax提交)
2019/09/01 Javascript
vue商城中商品“筛选器”功能的实现代码
2020/07/01 Javascript
[02:51]DOTA2 Supermajor小组分组对阵抽签仪式
2018/06/01 DOTA
Python对列表中的各项进行关联详解
2017/08/15 Python
Python3日期与时间戳转换的几种方法详解
2019/06/04 Python
打包python 加icon 去掉cmd黑窗口方法
2019/06/24 Python
pytorch 准备、训练和测试自己的图片数据的方法
2020/01/10 Python
解决jupyter运行pyqt代码内核重启的问题
2020/04/16 Python
Python并发concurrent.futures和asyncio实例
2020/05/04 Python
Django+Celery实现动态配置定时任务的方法示例
2020/05/26 Python
使用CSS3编写类似iOS中的复选框及带开关的按钮
2016/04/11 HTML / CSS
了解AppleShare protocol(AppleShare协议)吗
2015/08/28 面试题
《一个中国孩子的呼声》教学反思
2014/02/12 职场文书
党的群众路线教育实践活动宣传方案
2014/02/23 职场文书
学生请假条
2014/04/11 职场文书
2014年新生军训方案
2014/05/01 职场文书
战略合作意向书
2014/07/29 职场文书
安装工程师岗位职责
2015/02/13 职场文书
三十年再续同学情倡议书
2019/11/27 职场文书
Netty分布式客户端接入流程初始化源码分析
2022/03/25 Java/Android