组件化为什么选择 Component 而不是 ARouter

Posted 陈旭金-小金子

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了组件化为什么选择 Component 而不是 ARouter相关的知识,希望对你有一定的参考价值。

目录

前言

我们很多人都知道 ARouter, 也会优先选择 ARouter, 这篇文章将会阐述为什么你需要选择 Component, 而不是其他的.

评判标准

大部分人选择 ARouter 是因为没有其他很好的评判标准, 觉得它 star 多就觉得可以信赖, 所以大部分人都是跟风的去使用 ARouter, 难道除了 star 就没有其他很好的评判标准了吗?

组件化你到底想解决什么问题?

如标题, 你得先明白你对项目实施组件化到底是想解决什么问题, 而不是盲目的.首先你一定是想解决最核心、最基础的两点:

  • Activity 路由跳转
  • 跨模块的功能调用

有些框架可能把 Activity 路由跳转功能纳入 跨模块的功能调用 模块中, 也就是不直接提供路由的功能, 其实跨模块调用实现了, 你就可以自己实现 Activity 路由跳转

每一个框架都必须至少帮助开发者解决了跨模块的功能调用的这个问题, 这是一个框架的最最基础的.

组件化解决核心问题就够了吗

组件化解决核心问题了之后, 确实就可以着手组件化了, 但是组件化框架其实还可以提供更多, 去解决用户的痛点. 这在以前是基本上实现不了的!

除了核心问题其他的痛点

  • 路由跳转失败的降级处理
  • 路由跳转的拦截器
    • 页面拦截器(超级核心的功能,这个概念下文会介绍, 目前只看到 WMRouterComponent 框架是有这个设计的)
    • 全局拦截器(每个框架基本都有提供)
  • 类似 Retrofit 的接口调用(可以统一某些跳转, 提供统一的方法, 而不是到处复制, 便于维护)
  • 和用户有关的回调都应该是主线程(为什么下文解释)
  • 获取跳转目标的 ActivityResult (一个超级好用并且实用的功能)
  • 自定义目标界面的 Intent
  • 扩展支持 RxJava2

很多人可能对以上的很多点都没有很好的体会, 这里且让我慢慢说.

路由跳转失败的降级处理

这点我就不说了, 在很多场景这个功能是需要的, 因为跳转失败在以往原生写法是体现为奔溃, 而框架会收集错误并且统一处理的, 但是很多时候我们想跳转失败后希望跳转到一个特殊的页面去, 给用户一个友好的展示! 这就是降级的功能, 不是很必须, 但是有用.

路由拦截器

页面拦截器

为什么说这个功能是超级好用并且神奇的一个功能, 下面我举几个例子:

  • 你是如何实现需要登录的界面完成登录这个功能的
  • 假设一个界面 A 进入之前需要先验证传入的参数是否合法, 但是验证这个过程是一个网络请求. 而入口有 B, C, D 三处. 那么你是把验证的代码写在 A 还是写在 B, C, D?
  • 假设你一个界面 A 是需要相机权限的, 那么你申请权限是进入 A 再处理还是进入之前?

上面这些例子只是比较典型的一个例子, 这类的情况很多, 我不会全部举例出来, 但是他们有一个共同点, 那就是进入某一个界面之前需要做一个 预处理, 如果 预处理 失败了那么就不能够进入.

以往我们的写法无法两种

  • 写在每一个跳转发起的 Activity
  • 写在目标 Activity 里面, 当完成预处理, 展示对应错误 UI 或者销毁界面

这两种写法都会很恶心

  • 第一种写法会让每一个跳转发起的地方都写一样的 预处理 代码, 不写又不行, 写了又恶心

  • 第二种写法维护性是大大增强了, 因为代码在目标界面只写了一份, 但是这有一个很恶心的问题就是, 目标界面已经启动了, 当预处理失败之后, 对用户而言就会看到界面出来了又销毁了或者展示了一个错误视图, 展示错误视图这种已经是很好的处理了, 起码用户看的还挺舒服, 但是我们代码依旧写的很恶心

基于以上的, 页面拦截器应运而生, 目标就是解决此问题的

页面拦截器本质上是一个拦截器, 但是它不是一个全局拦截器, 当一个路由跳转到目标界面 A 之前, 框架会取出和 A 有关的拦截器, 并且执行这些拦截器, 执行成功才会跳转到目标界面.

这种方式就可以很好的解决上面我们的问题, 既不用在路由发起的地方去写这些 预处理 的代码, 也不用在目标界面里面去处理.

你可以为 A 目标界面声明一个页面拦截器, 预处理 代码就放在这里面. 完美的解决上述的问题!!

预处理 可以做任何的事情, 所以扩展性很强. 这是一个不可或缺的功能!!!

全局拦截器

全局拦截器就不说了, 每一个框架都有, 就是那种每一个路由跳转都能拦截到的拦截器

路由接口

路由接口是什么?它是一种可以允许用户用 类似 Retrofit 的接口调用, 完成一个路由跳转!

如下声明一个接口, 你可以描述一个方法为一个路由跳转, 然后你可以 如下方式调用

@RouterApiAnno()
public interface AppApi 
    @HostAnno("help")
    @PathAnno("testWeb")
    void goToTestWebRouter();


// 跳转
Router.withApi(AppApi.class).goToTestWebRouter();

这种方式有啥用呢? 因为有些界面的参数比较复杂, 可能有十几个, 你会发现你每次都写下面这么长一段跳转是很恶心的一件事, 所以框架允许你可以先把跳转用接口的方法给描述出来, 这样每个地方调用就只要调用方法传入参数就行了, 不需要关心 key 的问题! 这个功能不是非常必须, 但是十分有用!

Router
			.with(this)
      .host("app")
      .path("test")
  		.putString("name","cxj")
    	.putString("pass","123")
    	.putString("phone","158xxxxxxx")
    	.putString("desc","ccccccc")
  		......
  		......
  		......
      .navigate();

用户自定义的部分的执行线程都是主线程

为什么这点这么重要?因为我们写应用的时候, 几乎 95% 的代码都是在主线程上的, 我们很少写的代码在子线程上去运行!如果一个拦截器是需要弹框或者操作 UI 的, 那么 ARouter 之类的框架就会难受至极, 它只能在拦截器中去切换线程去做这件事, 其实设计上稍微变换一下, 采用 Callback 的形式就可以实现拦截器方法执行在主线程, 但是路由整体是可以 异步的

  • 路由跳转的回调
  • 拦截器的实现方法

目前就发现可能用户会用到的两个地方!

而很多人觉得路由跳转整体不是异步的吗?那拦截器的实现方法怎么可能在主线程执行. 类似于 OkHttp 的拦截器实现当然不行, 这个和拦截器的方法实现有关, 有兴趣的可以查看 Component 的拦截器实现

获取跳转目标的 ActivityResult (贼好用!!!)

我想这个功能就不用我说了把, 太重要了. 我说下以往的痛点吧! 以下情况都是会让开发者抓狂并且不得不做的事情

  • Adapter 中发现需要跳转界面拿 ActivityResult
  • Dialog 中发现需要跳转界面拿 ActivityResult
  • 自定义控件中发现需要跳转界面拿 ActivityResult
  • 其他不在 Activity 上但是持有 ActivityContext 的地方发现需要跳转界面拿 ActivityResult

你在以上地方跳转了, 但是你需要在 Activity 中拿到 拿到 ActivityResult , 这件事简直就是恶心, 因为它完全让我的代码分隔两地, 并且原本不需要 Activity 做处理却因为 android 的这个设计而不得不这么做.

这个功能就是来完全解放你的, 它可以让你在任何持有 Activity Context 的地方都可以跳转直接在回调中拿到 ActivityResult, 而不需要中断你的代码, 并且不需要在 Activity 中写任何代码!

自定义目标界面的 Intent

这个属于一个扩展功能, 但是也非常有用!

  • 你想为第三方界面或者系统界面也添加路由标记, 然后我们就可以使用路由跳转了!
  • 当第三方界面或者系统界面纳入路由体系, 你会发现它们也可以使用到页面拦截器等超好用的功能, 比如你跳转系统拍照界面的时候, 为它写一个申请拍照权限的页面拦截器, 超爽!
  • 你想为同一个界面写多个路由标记, 也就是多个 Path 对应一个界面

扩展支持 RxJava2

RxJava2 的火热程度不用我介绍了, 框架支持你扩展一个跳转是一个 [Observable], 在 wiki 中, 路由接口的方式使用下, 你可以让返回值是 [Observable]

  • void —> Completeable
  • Single 表示拿 Intent
  • Single 表示拿 ActivityResult
  • Single 表示拿 ActivityResultresultCode

比如下面的使用, 更多的用法请参照 源码中的例子

@RouterApiAnno()
@HostAnno(ModuleConfig.App.NAME)
public interface AppApi 
  
    @PathAnno("testQuality")
    Completable goToTestQuality();
  
    @RequestCodeAnno()
    @NavigateAnno(forResult = true)
    @PathAnno("testGetActivityResult")
    Single<ActivityResult> testGetActivityResult();
  

请相信 Component

请相信 Component 能带给你不一样的体验!
所有功能都是源自公司 App 组件化过程中遇到的痛点. 相信能给大家一个更好的组件化方案.

以上是关于组件化为什么选择 Component 而不是 ARouter的主要内容,如果未能解决你的问题,请参考以下文章

为啥使用无状态功能组件而不是基于类的组件?

什么时候应该使用组件数据而不是 vuex 状态?

Angular 2:在另一个组件上定义路由器而不是引导组件

React Emotion Styled Component:类选择器不起作用

Web设计规范----控件组件

视图组件(Component)