首页 >> 大全

Android路由实现

2023-09-12 大全 31 作者:考证青年

前几个月有幸参加了CSDN组织的MDCC移动开发者大会, 一天下来我最大的收获就是了解到了模块化开发, 回来之后我就一直在思考模块化的一些优点, 不说别的, 提供一种可插拔的开发方式就足够我们兴奋一会了~ 接下来自己开始尝试了一些小demo, 发现在模块化开发中最大的问题就是组件间通讯, 例如: 在模块化架构中, 商城和个人中心分别是两个独立的模块, 在开发阶段, 个人中心如何想要跳转商城的某个页面咋办? 这里就需要引入一个路由的概念了. 做过web开发的都知道, 在大部分web框架中url路由也是框架中很重要的组成部分, 如果大家对路由的概念还不是很清楚, 可以先来看一下我这篇go web开发之url路由设计来了解下路由的概念, 这里稍稍解释一下路由就是起到一个转发的作用.

一张图来体会一下路由的作用, 因为我本地没有UML工具, 新的还在下载中… 900M+, 我这网速有点受不了. 所以我选择手动绘制一张具有魔性的图片先来体会一下.

路由实现页面跳转_路由实现步骤_

自己实现一个路由的动机

那到了我们开发中呢? 如果我们把项目模块化了, 那两个组件间进行通讯或者跳转, 我们一般构建的方式就不再使用了, 很简单, 因为在模块A中根本找不到模块B中的C类, 这就需要我们自定义路由规则, 绕一道弯去进行跳转, 说白了就是给你的类起一个别名, 我们用别用去引用. 其实在我准备自己去实现一个路由的时候我是了一些解决方案的, 这些方案大致可分为两种.

完全自己实现路由, 完全封装跳转参数利用隐式意图跳转

对于这两种方式我总结了一下, 个人认为第一种方式封装的太多, 甚至有些框架是 like的, 这样的封装一是学习成本太高, 二是旧项目改动起来太麻烦. 那第二种方式呢? 利用隐式意图是一种不错的选择, 而且原生支持, 这也是大家在尝试模块化开发时的一个选择, 不过这种方式仅支持, , , 扩展性太差. 综上因素, 我还是决定自己实现一个路由, 参考自上面的局限性, 我们的路由具有一下2个特点.

上手简单, 目标是与原生方式一行代码之差就能实现, , 调用.扩展性强, 开发者可以任意添加自己的路由实现, 不仅仅局限于, , . 体验一下

在了解具体实现代码之前, 我们先来了解一下新的路由怎么使用, 使用起来是不是符合上面两点, 首先我们先建立三个, 分别是壳app, 商城模块, bbs模块. app模块就是我们的壳了, 我们需要利用app模块去打包, 而且app也是依赖和的, 所以我们可以在app的里进行路由的注册.

public class App extends Application {@Overridepublic void onCreate() {super.onCreate();setupRouter();}private void setupRouter() {Router.router(ActivityRule.ACTIVITY_SCHEME + "shop.main", ShopActivity.class);Router.router(ActivityRule.ACTIVITY_SCHEME + "bbs.main", BBSActivity.class);}
}

这里注册了两个路由, 分别是商城模块的的和bbs模块的, 它们都是通过类的静态方法方法进行注册的, 两个参数, 第一个参数是路由地址(也可以理解成别名), 第二个参数对应的类. 注册完了, 那接下来就是如何使用了, 我们来看看在商城模块如何跳转BBS模块吧.

public class ShopActivity extends AppCompatActivity {@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);TextView tv = new TextView(this);tv.setTextSize(50);tv.setText("SHOP!!!");setContentView(tv);tv.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Intent it = Router.invoke(ShopActivity.this, ActivityRule.ACTIVITY_SCHEME + "bbs.main");startActivity(it);}});}
}

主要代码是在click事件里, 我们调用了.方法, 第一个参数是当前, 第二个参数就是我们前面注册的路由了, 这里都很好理解, 关键是看它的返回值, 这里直接返回了一个, 这一点是最棒的~ 返回也就是说明下面的代码和我们使用原生方式没有任何区别! 这一点符合上面我们说到的上手简单的目的.

至于第二点目标, 高扩展性, 大家可以实现Rule接口自定义路由Rule, 然后调用.( , Rule rule)方法进行路由规则的注册. Rule接口的定义如下,

/*** 路由规则接口
* Created by qibin on 2016/10/8.*/
public interface Rule<T, V> {/*** 添加路由* @param pattern 路由uri* @param klass 路由class*/void router(String pattern, Class klass);/*** 路由调用* @param ctx Context* @param pattern 路由uri* @return {@code V} 返回对应的返回值*/V invoke(Context ctx, String pattern); }

解释一下, 首先是Rule接口的两个范型, 第一个T是我们注册的路由类型, 例如前面使用的类型, 第二个V是方法的返回值类型, 例如前面使用的类型.至于自定义的代码, 这里我赖了~, 没有提供demo~~~ 大家可以尝试自定义一下.

路由实现代码

接下来我们开始进入实现代码环节~ 在来是代码之前, 还是先来一张图了解下这个的结构.

_路由实现页面跳转_路由实现步骤

带着上面的图片, 我们来看代码, 首先我们来看看类, 毕竟我们在使用的时候都是在和打交道.

/*** Usage: 
*
* step 1. 调用Router.router方法添加路由* step 2. 调用Router.invoke方法根据pattern调用路由* 

* by qibin on 2016/10/9.*/ class {/*** 添加自定义路由规则* @param 路由* @param rule 路由规则* @ {@code } 真实调用类*/ ( , Rule rule) { = .get();.(, rule); ;}/*** 添加路由* @param 路由uri* @param klass 路由class* @ {@code } 真实调用类*/ ( , Class klass) { .get().(, klass);}/*** 路由调用* @param ctx * @param 路由uri* @ {@code V} 返回对应的返回值*/ V ( ctx, ) { .get().(ctx, );}}

哈, 的代码很简单, 主要就是起到一个类似静态代理的作用, 主要的代码还是在里, 那来看看的结构吧.

public class RouterInternal {private static RouterInternal sInstance;/** scheme->路由规则 */private HashMap mRules;private RouterInternal() {mRules = new HashMap<>();initDefaultRouter();}/*** 添加默认的Activity,Service,Receiver路由*/private void initDefaultRouter() {addRule(ActivityRule.ACTIVITY_SCHEME, new ActivityRule());addRule(ServiceRule.SERVICE_SCHEME, new ServiceRule());addRule(ReceiverRule.RECEIVER_SCHEME, new ReceiverRule());}/*package */ static RouterInternal get() {if (sInstance == null) {synchronized (RouterInternal.class) {if (sInstance == null) {sInstance = new RouterInternal();}}}return sInstance;}
}

首先是一个单例, 一个变量用来保存我们的路由规则, 在构造中我们注册了三个默认的路由规则, 这三个路由规则想都不用想就知道是, 和的. 接下来看看其他的方法.

/*** 添加自定义路由规则* @param scheme 路由scheme* @param rule 路由规则* @return {@code RouterInternal} Router真实调用类*/
public final RouterInternal addRule(String scheme, Rule rule) {mRules.put(scheme, rule);return this;
}

方法是添加路由规则的实现, 这里我们是直接向这个中添加的.

_路由实现页面跳转_路由实现步骤

private  Rule getRule(String pattern) {HashMap rules = mRules;Set keySet = rules.keySet();Rule rule = null;for (String scheme : keySet) {if (pattern.startsWith(scheme)) {rule = rules.get(scheme);break;}}return rule;
}

的作用是根据来获取规则, 这是一个私有的方法, 所以在使用的时候不需要关心, 它的原理很简单, 就是根据你的来匹配 来获取对应的Rule.

/*** 添加路由* @param pattern 路由uri* @param klass 路由class* @return {@code RouterInternal} Router真实调用类*/
public final  RouterInternal router(String pattern, Class klass) {Rule rule = getRule(pattern);if (rule == null) {throw new NotRouteException("unknown", pattern);}rule.router(pattern, klass);return this;
}

这个方法就是我们添加路由的实现了, 首先我们根据路由的uri来获取对应的Rule, 然后调用该Rule的 方法, 至于Rule.方法如何实现的, 我们稍后看~

/*** 路由调用* @param ctx Context* @param pattern 路由uri* @return {@code V} 返回对应的返回值*/
/*package*/ final  V invoke(Context ctx, String pattern) {Rule rule = getRule(pattern);if (rule == null) {throw new NotRouteException("unknown", pattern);}return rule.invoke(ctx, pattern);
}

方法就是我们调用的时候执行的代码的, 返回值T是返回的Rule范型中指定的类型, 例如前面的.

综上代码, 我们发现其实就是一个管理Rule的类, 具体的调用还是在各个Rule中实现, 上面提到过, Rule是一个接口, 它具有两个范型, 分别对应的调用 的返回值类型和我们要路由的类的类型. 解析来我们就来看看默认的几个路由规则是如何实现的.

对于, , 的调用, 总结了一下, 它们其实都是返回的类型, 所以我们可以先构建一个指定返回值是的Base类型.

/*** 返回Intent的路由规则的基类
* Created by qibin on 2016/10/9.*/
public abstract class BaseIntentRule<T> implements Rule<T, Intent> {private HashMap> mIntentRules;public BaseIntentRule() {mIntentRules = new HashMap<>();}/*** {@inheritDoc}*/@Overridepublic void router(String pattern, Class klass) {mIntentRules.put(pattern, klass);}/*** {@inheritDoc}*/@Overridepublic Intent invoke(Context ctx, String pattern) {Class klass = mIntentRules.get(pattern);if (klass == null) { throwException(pattern);}return new Intent(ctx, klass);}/*** 当找不到路由规则时抛出异常* @param pattern 路由pattern*/public abstract void throwException(String pattern); }

方法不多说, 还是向Map中添加键值对, 方法, 我们通过参数中的从目标类, 然后构建一个返回, 最后一个是一个抽象方法, 用来在调用没有的类时抛出异常用~, 可以发现, 其实大部分的实现在这里都实现了, 对于继承这个,并且指定要路由类的类型是, 并且实现方法就可以了.

/*** activity路由规则
* Created by qibin on 2016/10/8.*/
public class ActivityRule extends BaseIntentRule<Activity> {/** activity路由scheme*/public static final String ACTIVITY_SCHEME = "activity://";/*** {@inheritDoc}*/@Overridepublic void throwException(String pattern) {throw new ActivityNotRouteException(pattern);} }

首先继承了并指定了范型是, 实现的方法也很简单, 就是抛出了一个ption异常, 对于这个异常, 大家可以在文章最后的源码下载部分找到~ 看完的实现, 其实其他两个默认Rule的实现都一样了~ 大家也是自己去看代码吧.

其实实现一个路由很简单, 原理就是给我们要路由的类定义一个别名, 然后在调用的地方通过别名去调用. 而且在封装的时候尽量要符合现在用户的使用习惯, 不要过多的封装而忽略了使用者的感受.

好了, 这篇文章就到这里了, 文章中的代码大家可以到一个模块化开发的小demo中找到~

关于我们

最火推荐

小编推荐

联系我们


版权声明:本站内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 88@qq.com 举报,一经查实,本站将立刻删除。备案号:桂ICP备2021009421号
Powered By Z-BlogPHP.
复制成功
微信号:
我知道了