使用 Router 实现的模块化,如何优雅的回到主页面

版权声明:

本账号发布文章均来自公众号,承香墨影(cxmyDev),版权归承香墨影所有。

未经允许,不得转载。

一、前言

现在越来越多的 App 以 Router 路由的形式,来实现模块化。一般而言,这种 Router 的方案,从外部直接调起的方式,是由一个 ProxyActivity 做一个代理,然后再由它去跳转到项目内的其他目标 TargetActivity 。这样的实现,理论上,是可以从外部调起 App 内所有的 Activity 的。

但是这样就面临一个问题,如果从外部调起了一个子页的 Activity,举例是一个影片详情页,如果想在用户回退的时候,进入到应用主页,而非直接退出了。就需要特殊处理了。

本文就以如何优化的回退到我们需要的 Activity 来做一个说明。

二、分析和拆解问题

对于前面举例的情况来说,实际上我们只需要处理好以下问题即可。

  1. 如何区分当前 Activity 是从应用内打开,还是从应用外直接打开,就是打开 Activity 的来源。
  2. 在区分出来 Activity 打开的来源之后,如何优雅的退回到我们需要的 Activity。
  3. 要处理一些特殊情况。

对于这样两个问题,区分来源,最粗暴的方式,就是在 Intent 里增加一个类似 from 的字段,来标记是从那个页面过来的,如果不是我们指定的话,在 finish() 或者 onBackPressed() 的时候,就打开 MainActivity 即可。

这是一个粗暴的方式,虽然它有用,可它不够优雅。

而在 Support v4 22.0.0 开始,针对这样的情况,为我们增加了一个 NavUtils 的类,专门用于处理这种情况,接下来就来看看如何使用它。

三、NavUtils 如何使用

NavUtils 从名称上就可以看出来,它是一个用于处理导航的辅助工具类。

先来看看它的方法,它主要的方法主要分三中:

  • getParentActivityIntent():获得一个用户回退到父Activity 的Intent。
  • shouldUpRecreateTask():是否需要重新构建一个 Task。
  • navigateUpTo():回退到 Intent 指定的父 Activity。

为了方便使用 getParentActivityIntent() 提供了很多的重载,但是实际上目的都是一样的,就是拿到我们指定的当前 Activity 的上一级 Activity(父 Activity )。

既然是 Support v4 包下的辅助类,它其实在内部也是做好了很多兼容的处理。它针对不同的 Android Level 做了不同的实现,可以看到 NavUtilsImplBaseNavUtilsImplJB 都是为了处理兼容性的问题,他们都实现了 NavUtilsImpl 接口,而且在静态代码块内处理好了兼容性问题。

好了,源码就先聊到这里,先来看看如何使用。

如果想要使用 NavUtils 还需要在 AndroidManifest.xml 中,为 Activity 指定一个父的 Activity。

这里有个 Demo ,有两个 Activity,分别是 MainActivity 和 ChildActivity 。我们需要对 ChildActivity 设定父 Activity。

为 Activity 设定父 Activity,是需要区分版本的,在 4.1 之后,是可以直接使用 android:parentActivityName 直接指定即可。而对于 4.0 及一下的版本,如果想要使用,可以配置 meta-data 标签,name 必须是 android.support.PARENT_ACTIVITYvalue 就是用来指定父 Activity 的。

先来看看官方推荐的使用示例。

它的流程非常的简单,首先使用 NavUtils.getParentActivityIntent() 方法,获得它的父 Activity,然后使用 NavUtils.shouldUpRecreateTask() 方法,确定当前 Activity 是否需要一个 Task ,如果需要,使用 TaskStackBuilder 来操作,如果不需要就直接调用 NavUtils.navigateUpTo() 方法来继续接下去的逻辑。

可以看到这一套逻辑,非常的简单,如果按照文档的描述,使用起来应该体验挺不错的,但是它有坑,后面讲。

三、NavUtils 的源码

先来看看 NavUtilsImplBase 这个 Api Level 16 以下的 Api 实现,它因为没有一些高版本的 Api,从源码上能看出跟多细节。

简单关注一下它的细节,shouldUpRecreateTask() 方法,实际上是通过校验 Action 是否等于 ACTION_MAIN 来确定的,而 navigateUpTo() 只是为 upIntent 添加了 FLAG_ACTIVITY_CLEAR_TOP 这个 flag ,然后启动父 Activity 并且关闭自己。而 getParentActivityIntent() 的代码,其实核心还是在 NavUtils.getParentActivityName() ,最终可以看到,它和我们配置的一样,是从 meta-data 中获取的数据。

再来看看 NavTilsImplJB 这个 Api Level 16 上的实现。

可以看到,它其实很多逻辑都放在 NavUtilsJB 这个类中。

而它实际上很多方法都是直接调用的 Activity 中对应的方法,有兴趣可以去看看 Activity 的源码中的实现。

四、填坑和最终实现

到这里,基本上就已经了解了 NavUtils 的实现原理了,看样子用起来应该没那么多问题,但是如果实际使用起来,你就会发现有坑了。

1、shouldUpRecreateTask() 永远返回的是 false。

实际上,这并不是 shouldUpRecreateTask() 方法在实现上有什么 Bug,它实际上是给 Notification 使用的,在 Notification 使用 PendingIntent 的时候,使用 TaskStackBuilder 来构建它,其构造一个 Back Task ,在这里就可以使用 shouldUpRecreateTask() 方法来做判断了。

但是大多数情况下,我们并不只是在 Notification 中使用它,并且有一些推送的消息,这个 Notification 并非我们去构造的,而是由第三方 SDK 来构建的,这就导致这种情况并不符合大多数场景。

下面是官方提供的一个 Demo。

有兴趣可以移步到官方文档查看:

https://developer.android.com/guide/topics/ui/notifiers/notifications.html#NotificationResponse

所以我们可以使用 Activity.isTaskRoot() 来做辅助判断,它是 Activity 的方法,可以判断当前 Activity 是否是在当前 Task 的根 Activity,这样就说明再回退的话,实际上就会将当前 Task 完整的清空,表现就是退出去了。

2、navigateUpTo() 会重新启动MainActivity

navigateUpTo() 方法从源码上可以看出来,它实际上是强加了一个 FLAG_ACTIVITY_CLEAR_TOP ,然后重新启动它,这样的话,在某些设备上,默认是有动画处理的,因为这里是打开了一个新的页面,而非 finish() 之后,自动回退到上一个页面的操作。

那么解决方案也非常的简单,在判断当前 Activity 不需要使用 TaskStackBuilder 构造一个 Task Stack ,就直接 finish() 掉当前的页面,因为这样的判断说明当前 Activity 是在页面内正常打开的,所以直接 finish() 就可以退回到上一个页面了。

最终改动之后的实现效果就变成了这样,AndroidManifest.xml 中的配置不变。

使用 Router 实现的模块化,如何优雅的回到主页面的更多相关文章

  1. Node.js_ express.Router 路由器_模块化管理路由

    路由器 express.Router 路由器 模块化管理 路由 基本使用: 路由模块 1. 引入 express const express = require('express'); 其他相关模块 ...

  2. 在vue中优雅地实现简单页面逆传值

    [需求] 要实现的需求很简单,页面从A -> B,用户在B触发操作,将一些数据带回到A页面,在网上找了好久也只看到有人问,但总找不到很好答案.要实现的效果图如下: [联想] 在 ios 开发中, ...

  3. 在APP开发中,如何优雅的设计APP页面

    1.明确页面设计在整个产品设计中的位置 互联网产品设计的流程大致是:产品定位——需求分析——信息架构设计——流程设计——页面框架设计——设计说明——输出设计文档.可以看到页面设计是处于整个流程的后期, ...

  4. 如何优雅的设计APP页面?

    页面框架设计只是整个产品设计中的一环,不要把眼界局限在这一环,也不要只站需求.只站在交互.只站在视觉上思考问题,从多个角度看问题,你才会学会成长. 产品设计是一个系统工程,单独拧出来其中一个流程来讲, ...

  5. 利用Jenkins自动部署工具间接构建kettle的调度平台

    关于Jenkins的介绍我就不说了,自己百度,因为这个工具调用脚本只是他的功能的冰山一角,其他功能我也不能理解,因为不是那个领域.        下面我就介绍一下为什么我们需要一个调度平台,以及学习完 ...

  6. #WEB安全基础 : HTML/CSS | 0x9美丽的饮料店

    我带着你,你带着钱,咱们去喝点饮料吧. 老板久仰你的大名,请你帮忙设计一个网站宣传他的饮料店 你要制定一个完美的方案还需要多学点东西 我先帮你设计一下 这是存放网站的文件夹 这是根目录   这是abo ...

  7. 利用端口映射解决:拥有公网IP有限,内网需要访问因特网

    动态端口映射:   内网中的一台电脑要访问新浪网,会向NAT网关发送数据包,包头中包括对方(就是新浪网)IP.端口和本机IP.端口,NAT网关会把本机IP.端口替换成自己的公网IP.一个未使用的端口, ...

  8. express 将 Router 实例模块化

    为了更好的组织代码,将 Router 实例进行模块化,将 get / post 等快捷方式放在Router上,而不是 App 上,然后将该 Router 作为中间件,use 到 server.js 上 ...

  9. (札记)Java应用架构设计-模块化模式与OSGi

    本书主要模块化模式的优点.模块化方法与模式.OSGi简单使用等内容.分3大部分: 第一部分介绍了模块化概念.为什么要模块化,以及一些模块化要考虑的东西,如模块粒度,依赖关系,重用性灵活性等. 第二部分 ...

随机推荐

  1. MYSQL更改root password时遇到Access Denied的解决办法

    今天在公司虚拟机上装MYSQL之后需要修改root password,然而遇到这样的错误: Access denied for user 'root'@'localhost' (using passw ...

  2. (原创)用JAX-WS+Spring实现简单soap规范的webservice

    转载请注明出处:http://www.cnblogs.com/Starshot/p/7050084.html Soap即简单对象访问协议,也可理解为一种用于程序之间通讯的规范,它主要基于XML和htt ...

  3. Python os模块--路径、文件、系统命令等操作

    os模块包含普遍的操作系统功能. 注意:函数参数path是文件或目录的路径,filename是文件的路径,dirname是目录的路径,路径可以是相对路径,也可绝对路径 常见或重要的函数为加粗字体 os ...

  4. .htaccess伪静态(URL重写)绑定域名到子目录实现子站点

    Apache主机一般支持.htaccess伪静态,即可以实现绑定域名到子目录.一个空间多个站点. 应用举例:绑定htaccess.800m.net到htaccess目录 根目录下.htaccess内容 ...

  5. ecshop商品页增加编辑器fckeditor

    最近在做ecshop的项目,需要在商品单页中增加一项FCKEditor的文本编辑器,但在ecshop的论坛和百度里搜出的方法,试了好几个都没有用,终于找到一个可以正确使用的,和大家分享. ecshop ...

  6. 常见License错误代码

    2017-06-2816:32:40 -1 找不到许可文件. -2 无效的许可文件语 -3 没有用于此功能的 -4 已达到许可的用户 -5 不存在此功能. -6 许可文件中没有 TCP/IP 端口号, ...

  7. Web直接导入导出SHP/CAD实现探讨。

    1.导入SHP/CAD文件 WEB具有直接美观展现功能,功能实现到可视化最好不要超过3S,那么就要限制导入文件的大小和优化算法了. 1.1.SHP导入实现思路 SHP格式开源,Git上随便可以找到读取 ...

  8. CSS样式表之常用文本属性

    断更了两周了,因为纠结之后在学java啦,但是还是要把学过的前端知识更完 以下的一些文本属性是CSS最常用的属性: [长度单位]:px(像素) [颜色单位]: 十六进制:#ffffff 分别对应红绿蓝 ...

  9. C++ 派生类到基类转换的可访问性

    今天看c++ primer关于派生类到基类转换的可访问性,看的很晕,看了下面的文章恍然大悟: http://www.2cto.com/kf/201403/283389.html C++ primer第 ...

  10. EF查询百万级数据的性能测试

    一.起因  个人还是比较喜欢EF的,毕竟不用写Sql,开发效率高,操作简单,不过总是听人说EF的性能不是很好,也看过别人做的测试,但是看了就以为真的是那样.但是实际上到底是怎么样,说实话我真的不知道. ...