在Android上导航-过去,现在和将来

Navigation is an essential element of every Android app. It should be fast, intuitive and reliable. Good navigation patterns are natural to the user, providing a seamless flow without ever having to think about it. In this article I will briefly look back at how navigation traditionally was done on Android and the pitfalls and caveats that came with it. I’ll discuss the introduction of the Navigation Component library (‘NCL’) in 2018 and see if the NCL is mature enough for a large production app in 2020.

导航是每个Android应用程序的基本元素。 它应该是快速,直观和可靠的。 良好的导航模式对用户来说很自然,无需考虑即可提供无缝的流程。 在本文中,我将简要回顾一下传统上在Android上是如何进行导航的,以及它所带来的陷阱和警告。 我将在2018年讨论导航组件库 ('NCL')的引入,并查看2020年该NCL是否足够成熟以适合大型生产应用程序。

Old routesTraditionally, on Android, you would use an Activity for every screen. If you were to navigate from one screen to another you would send the Android Framework your implicit or explicit Intent and the Framework would then try to launch the next Activity.

旧路线传统上,在Android上,您将在每个屏幕上使用“活动”。 如果要从一个屏幕导航到另一个屏幕,则可以向Android框架发送您的隐式或显式Intent,然后该框架将尝试启动下一个活动。

Activities are like islands; they provide entry points to your application and basically enable you to display data. Since Activities are 100% distinct from one another, sharing data between them is only possible either through disk, singletons or Intent arguments. Due to this fundamental design decision from the early days of Android, it is effectively not possible to share ViewModels between different activities. Every time you launch a new Activity, you ask the Android Framework to essentially create a new entry point for your app, usually only to display some different data. Having one or a very limited number of Activities inside your app improves UI transitions, makes sharing data between screens easier and prevents Activity lifecycle issues. A more in depth analysis and discussion of the benefits of the single Activity model can be found here.

活动就像岛屿; 它们为您的应用程序提供了入口点,并且基本上使您能够显示数据。 由于活动彼此之间存在100%的差异,因此只能通过磁盘,单例或Intent参数在它们之间共享数据。 由于Android早期的这一基本设计决策,实际上不可能在不同活动之间共享ViewModel。 每次启动新的Activity时,您都要求Android Framework本质上为您的应用创建一个新的入口点,通常只是为了显示一些不同的数据。 应用程序内部包含一个或数量非常少的Activity可以改善UI转换,使屏幕之间的数据共享更加轻松,并避免Activity生命周期问题。 在这里可以找到更深入的分析和对单个活动模型的好处的讨论。

Image for post
Activities inside an app are like a group of islands 应用内的活动就像一群孤岛

It is possible to use Fragments instead of Activities. But usually this would entail to manually performing Fragment transactions and managing the back stack (and possibly an additional ‘up stack’ for when the ‘up’ button has different navigation behavior). This is tedious and error prone. The NCL promises to address these issues and promotes the use of the single Activity pattern with multiple Fragments as ‘destinations’.

可以使用片段代替活动。 但这通常需要手动执行Fragment事务并管理后退堆栈(如果“向上”按钮具有不同的导航行为,则可能需要附加的“向上堆栈”)。 这是乏味且容易出错的。 NCL承诺解决这些问题,并促进将带有多个片段的单个活动模式用作“目的地”。

New turn Google introduced the NCL at the I/O developer festival in May 2018. It basically consists of 3 ‘N’s’.

新变化 Google在2018年5月的I / O开发人员节上推出了NCL。它基本上由3个“ N”组成。

· NavGraph, an XML resource file that contains all your destinations and navigation actions· NavController, object to perform navigation actions inside the NavGraph· NavHostFragment, an empty container to swap Fragments in and out

· NavGraph ,一个包含所有目标和导航操作的XML资源文件· NavController ,用于在NavGraph内部执行导航操作的对象· NavHostFragment ,一个空容器,用于将片段进出交换

These 3 elements combined make up the NCL. The idea is to use a very limited number of activities in your app (or even just 1). The Activity will serve as an entry point into your app and manage global navigation with use of a BottomNavigationView or alternative UI element. Your apps’ content will be displayed inside the NavHostFragment. The NCL performs all the Fragment transactions, provide type safe ways to share data between screens (SafeArgs) and let you scope a ViewModel to a NavController. For a further introduction I refer you to the well written official documentation.

这三个要素的总和构成了NCL。 这个想法是在您的应用程序中使用非常有限的活动(甚至只有1个)。 该活动将用作您应用程序的入口,并使用BottomNavigationView或其他UI元素管理全局导航。 您的应用程序的内容将显示在NavHostFragment中。 NCL执行所有Fragment事务,提供类型安全的方式在屏幕之间共享数据( SafeArgs ),并允许您将ViewModel 范围限定为NavController。 有关进一步的介绍,请参考精心编写的正式文档

All this sounds great. At Egeniq we are currently building a large travel app with over 100+ screens. Since it’s been almost 2 years since the library was released, we decided to try the NCL and see how all these promises would pan out.

所有这些听起来很棒。 目前,在Egeniq,我们正在构建具有超过100多个屏幕的大型旅行应用程序。 自从库发布以来已经快两年了,我们决定尝试NCL,看看所有这些承诺将如何实现。

Lengthy pathsBefore we dive into the details it’s important to note that modern Android smartphones are slimming down their screen bezels every new iteration. This means screens are getting taller. In 2015 the majority of smartphones had a 16:9 aspect ratio, in 2020 this has shifted to 20:9 or even taller. The body width of the mainstream phones has remained equal at around 70–75mm. Since many people use their phone with one hand, reaching the top corners is getting more difficult. Many app developers have recognized this trend and started replacing top navigation UI elements like Toolbars and DrawerLayouts in favor of a bottom navigation menu. Of course, Google is also aware of this trend so the NCL has first class support for navigating through a BottomNavigationView.

漫长的道路在我们深入研究细节之前,需要注意的是,现代Android智能手机在每次新迭代中都在缩小其屏幕边框。 这意味着屏幕越来越高。 2015年,大多数智能手机的宽高比为16:9,到2020年,该比例已提高到20:9甚至更高。 主流手机的机身宽度一直保持在70-75毫米左右。 由于许多人只用一只手使用手机,因此到达顶部角落变得越来越困难。 许多应用程序开发人员已经意识到了这种趋势,并开始使用顶部导航菜单来替换顶部导航UI元素(如工具栏和DrawerLayouts)。 当然,谷歌也意识到了这一趋势,因此NCL拥有通过BottomNavigationView导航的一流支持。

Image for post
Youtube, Spotify, Twitter, Netflix and many other flagship Android apps use a bottom navigation menu Youtube,Spotify,Twitter,Netflix和许多其他旗舰Android应用程序使用底部导航菜单

Taking the tourOur experience with the basics of navigation with the NCL were pretty good. Navigating from one screen to another is just 1–2 lines of code and drawing an arrow inside the Navigation editor. We used SafeArgs to pass data between different destinations inside the navigation graph. We also scoped a ViewModel to the current NavController when we had multiple Fragments inside the same Activity. This was a nice alternative to SafeArgs when we wanted to share data between Fragments that were visible on the same screen.

游览我们在NCL导航方面的基本经验非常好。 从一个屏幕导航到另一个屏幕仅需1-2行代码,并在Navigation编辑器中绘制箭头。 我们使用SafeArgs在导航图中的不同目的地之间传递数据。 当我们在同一个Activity中有多个Fragment时,我们还将ViewModel的作用域范围设置为当前的NavController。 当我们想在同一屏幕上可见的Fragments之间共享数据时,这是SafeArgs的不错选择。

Since our app has so many screens, it’s very convenient to have the Navigation Editor provide a visual overlay of the way users would navigate through the app. As a developer this enables you to verify if the mental model a user needs to make in their head is logical and not too complicated. It also made discussing the app functionality with the designer easier. Difficulties arose when we wanted to have multiple back stacks for the five ‘top level’ destinations a user could reach through the bottom navigation menu.

由于我们的应用程序具有许多屏幕,因此导航编辑器提供用户在应用程序中导航方式的直观覆盖非常方便。 作为开发人员,这使您可以验证用户需要在脑海中建立的思维模型是否合乎逻辑且不太复杂。 这也使与设计人员讨论应用程序功能更加容易。 当我们想要为用户可以通过底部导航菜单到达的五个“顶级”目的地提供多个后排堆叠时,就出现了困难。

Traversing historyA common scenario for our app would be a user scrolling through our ‘home’ page which contained a long list of videos and select a certain video to see more details. Then the user could decide to go into ‘notifications’ to check if someone in the video sent him a message earlier. When the user would navigate back to ‘home’ through the bottom navigation menu they would expect to see the detailed video screen intact. Secondly, the user would expect to be able to return to the same scroll position in the video list on ‘home’. The NCL library does not support multiple back stacks (as of version 2.2.2 — released in April 2020). This seemed like a deal breaker for us, since it’s a core requirement for our app. It’s questionable why the default behavior for the NCL is to clear the back stack and lose all UI state when switching between bottom tabs. On iOS this is not the case and we feel for most apps this provides a better user experience.

遍历历史记录对于我们的应用程序,常见的情况是用户滚动浏览“主页”页面,其中包含一长串视频,然后选择某个视频以查看更多详细信息。 然后,用户可以决定进入“通知”,以检查视频中是否有人较早地向他发送了消息。 当用户通过底部导航菜单导航回到“家”时,他们希望看到完整的详细视频屏幕。 其次,用户希望能够返回到“家庭”视频列表中的相同滚动位置。 NCL库不支持多个反向堆栈(自2020年4月发布的2.2.2版开始)。 对于我们来说,这似乎是一笔大买卖,因为这是我们应用程序的核心要求。 令人怀疑的是,为什么NCL的默认行为是在底部选项卡之间切换时清除后退堆栈并丢失所有UI状态。 在iOS上并非如此,我们认为对于大多数应用程序来说,这提供了更好的用户体验。

Image for post
The five top level destinations for our travel app 我们旅行应用程序的五个顶级目的地

Unpaved waysLuckily we found an advanced Google sample which has a workaround solution to provide multiple back stacks in conjunction with the NCL.

未铺砌方式幸运的是,我们发现其中有一种变通方法解决与NCL一起提供多个背叠先进的谷歌样品。

The idea is to have a separate NavGraph for each of the top level destinations (so five for our app). The sample contained an extension function on BottomNavigationView which set up a FragmentManager, a list of NavGraphs, a NavHostFragment and a NavController wrapped in a MutableLiveData object. It would then basically create a separate NavHostFragment and NavController for each of the 5 ‘top level’ destinations so they would have their own separate back stacks. The FragmentManager would push and pop Fragments on or off the back stack as the user navigated inside one of the five NavGraphs. The first Fragment was excluded to provide a ‘fixed’ start destination. The user could switch to another NavGraph while leaving the previous back stack intact by saving it to a Bundle.

我们的想法是为每个顶级目的地都有一个单独的NavGraph(对于我们的应用程序来说,有五个)。 该示例在BottomNavigationView上包含一个扩展功能 ,该功能设置了FragmentManager,NavGraphs列表,NavHostFragment和NavController包裹在MutableLiveData对象中。 然后,它将基本上为5个“顶级”目的地中的每个目的地创建一个单独的NavHostFragment和NavController,因此它们将拥有自己的单独的后置堆栈。 当用户在五个NavGraphs之一中导航时,FragmentManager会将Fragments推入或弹出后栈。 排除了第一个片段以提供“固定的”起始目的地。 用户可以通过将另一个NavGraph 保存到Bundle中来切换到另一个NavGraph,同时保持其后退堆栈不变。

Image for post
Multiple navigation graphs inside Android studio Android Studio中的多个导航图

We implemented this workaround in our app and it seems to do the job. We are going to test it more thoroughly in the future when our codebase and number of screens expands. The Navigation Component team at Google is currently working on getting multiple back stack support into the NCL. Their goal was to already implemented it in version 2.3.0, but they ran into issues. We feel it’s an important step towards further adoption of the library by the Android community, since many flagship Android apps have a bottom navigation menu with multiple back stacks (like Google’s own YouTube app, LinkedIn, Netflix and many more).

我们在应用程序中实施了此变通办法,并且似乎可以完成任务。 将来,随着代码库和屏幕数量的扩展,我们将对其进行更彻底的测试。 Google的导航组件团队目前正在努力为NCL提供多个后置堆栈支持 。 他们的目标是已经在2.3.0版中实现了,但是遇到了问题。 我们认为这是迈向Android社区进一步采用该库的重要一步,因为许多旗舰Android应用程序都有一个底部导航菜单并带有多个后退堆栈(例如Google自己的YouTube应用程序,LinkedIn,Netflix等)。

Wrap upNavigation is an essential element of every Android app. And it has come a long way on Android. Overall our experience with the NCL library was pleasant and the basics work well. To provide a quick summary:

总结导航是每个Android应用程序的基本要素。 在Android上已经走了很长一段路。 总体而言,我们在NCL库中的经验令人愉快,并且基础知识运行良好。 提供快速摘要:

Things we really liked were:

我们真正喜欢的东西是:

· A quick, visual and comprehensive overview of all the screens in the app. This also makes it easier to add new developers to the team and get them up to speed· Navigating from one screen to another and passing data is just 1–2 lines of code and drawing an arrow inside the Navigation editor.· SafeArgs is a nice type, safe way to share data between Fragment destinations· Scoping a ViewModel to a NavController to share data with multiple Fragments inside the same screen. This provides data encapsulation and safety.· NCL lets you adopt the single activity model easily and gain all the previously mentioned benefits that come with it.

·快速,直观,全面地查看应用程序中所有屏幕。 这也使将新开发人员添加到团队中并使其快速入门变得更加容易。从一个屏幕导航到另一个屏幕,传递数据只是1-2行代码,并在Navigation编辑器中绘制箭头。一种在片段目标之间共享数据的安全方式。将ViewModel设置为NavController,以与同一屏幕内的多个片段共享数据。 这提供了数据封装和安全性。NCL使您可以轻松地采用单一活动模型,并获得其附带的所有前述好处。

Things to improve:

有待改进的地方:

· Built-in support for multiple back stacks· Change the default behavior so that switching between tabs within a bottom navigation menu will not reset the back stack and save UI state (like iOS does)

·内置对多个后退堆栈的支持·更改默认行为,以便在底部导航菜单内的选项卡之间切换不会重置后退堆栈并保存UI状态(就像iOS一样)

If the NCL would support the more complex navigation cases out of the box (like multiple back stacks) we feel the library is mature enough to use in large production apps. With the NCL, building navigation for your app is fast and easy to implement. Secondly it makes shifting to the single Activity model a breeze and with that it enables you to improve the architecture and robustness of your app.

如果NCL可以开箱即用地支持更复杂的导航情况(例如多个后退堆栈),我们会认为该库已经足够成熟,可以在大型生产应用中使用。 使用NCL,可以快速轻松地为您的应用构建导航。 其次,它使轻而易举地转移到单个活动模型,并由此使您能够改善应用程序的体系结构和健壮性。

翻译自: https://medium.com/@rvbsoftdev/navigation-on-android-past-present-and-future-dcc9412748e1

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值