深入理解Navigation架构之setPrimaryNavigationFragment接管系统的导航操作

简介: 深入理解Navigation架构之setPrimaryNavigationFragment接管系统的导航操作

1.前言


不管你之前用没用过Jetpack Navigation组件,但是或多或少你也可能听说过它。它是Jetpack库中的一个路由组件。此刻你的脑海中可能会浮现阿里ARouter框架。如果你熟悉ARouter但是对Navigation比较陌生,那么你先简单把它们联系在一起,有个直观的感受。


如果你对ARouter和Navigation都不太熟悉,没关系,并不影响你对本文的阅读。

Navigation支持Activity、Fragment、Dialog的路由跳转,功能非常强大。此刻灵魂拷问一下。


你知道Navigation是如何实现Activity、Fragment组件的跳转吗?

你知道Navigation如何接管系统返回键操作的?


第一个问题,在不看源码的情况下,我们大概也能略猜一二,Activity的路由是通过startActivity(intent)方法来实现的,Fragment的路由是通过FragmentTransaction的replace方法来实现的。关于真正的跳转原理,之后会出专文讲解,敬请关注本公众号,及时获取更文通知。


第二个问题,在不深入理解源码的情况下,如果被问到,我会直接被问懵。难道是重写onBackPressed()?


好了,不卖关子了,Navigation组件是通过FragmentTransaction.setPrimaryNavigationFragment()方法接管系统返回键操作的。有源码为证:


//NavHostFragment.java
public void onAttach(@NonNull Context context) {
    super.onAttach(context);
    // TODO This feature should probably be a first-class feature of the Fragment system,
    // but it can stay here until we can add the necessary attr resources to
    // the fragment lib.
    if (mDefaultNavHost) {
        getParentFragmentManager().beginTransaction()
                .setPrimaryNavigationFragment(this)
                .commit();
    }
}


NavHostFragment从字面意思理解,它是Navigation组件的导航宿主组件。Fragment组件如果想要在Navigation框架中实现路由功能必须满足两个条件:


  1. Fragment必须依附在NavHostFragment上
  2. NavHostFragment必须成为PrimaryNavigationFragment(后文简称:主导航Fragment)


行文至此,你可能有点懵,但是没关系,你只需要知道有主导航Fragment这个概念就行,接着往下看


本文的主角是setPrimaryNavigationFragment(),它是Fragment框架中的方法,它并不是什么新鲜玩意,它跟随Fragment框架一起发布的。但是很吊诡地是,翻遍所有的技术社区,都很难找到讲解它的文章。但是它真的很重要,它是Navigation组件的基础设施(水和电)。


要想深入理解Navigation实现原理,必须对Fragment实现原理深入了解。FragmentTransaction、BackStackRecord、FragmentManager等概念必须成竹于胸。推荐阅读深入理解Navigation架构之Fragment基础一文,扎扎实实掌握Fragment知识。

说回NavHostFragment


//NavHostFragment.java
public class NavHostFragment extends Fragment implements NavHost {
    public void onAttach(@NonNull Context context) {
        super.onAttach(context);
        // TODO This feature should probably be a first-class feature of the Fragment system,
        // but it can stay here until we can add the necessary attr resources to
        // the fragment lib.
        if (mDefaultNavHost) {
            getParentFragmentManager().beginTransaction()
                    .setPrimaryNavigationFragment(this)
                    .commit();
        }
    }
}


很简单的几行代码,却藏着不少信息


  1. NavHostFragment是导航宿主Fragment,要实现路由跳转的Fragment都是它的child Fragment。这里就涉及到childFragmentManager,parentFragmentManager等知识了。
  2. mDefaultNavHost是要设置成true,NavHostFragment才能成为主导航Fragment。
  3. 从注释中,可以看出,setPrimaryNavigationFragment()虽然很不起眼,它即将升级为Fragment的一类公民了(first-class)。


2. FragmentManager 回退栈



栈是一种很简单的数据结构。它的特点是“后进先出”。在FragmentManager中回退栈定义如下:


public abstract class FragmentManager{
    ArrayList<BackStackRecord> mBackStack;
}


在FragmentTransaction中有addToBackStack(String name)方法,可以将某个方法加入回退栈中。


class FragmentActvitiy1: AppCompatActivity() {
  fun addFragmentNotAddToBackStack() {
      supportFragmentManager.commit {
            setReorderingAllowed(true)
            add<AFragment>(R.id.top_fragment_container_view)
      }
      supportFragmentManager.commit {
            setReorderingAllowed(true)
            add<BFragment>(R.id.top_fragment_container_view)
      }
  }
}
class FragmentActvitiy2: AppCompatActivity() {
  fun addFragmentNotAddToBackStack() {
      supportFragmentManager.commit {
            setReorderingAllowed(true)
            add<AFragment>(R.id.top_fragment_container_view)
            addToBackStack(null)
      }
      supportFragmentManager.commit {
            setReorderingAllowed(true)
            add<BFragment>(R.id.top_fragment_container_view)
            addToBackStack(null)
      }
  }


上述两段代码,唯一的区别就是FragmentActivity1没有调用addToBackStack()方法,而


image.png

FragmentActivity2调用了。

image.png

FragmentActivity1 按返回键效果如下:

image.pngFragmentActivity2 按返回键效果如下:

image.png

image.png


3. FragmentManager处理返回原理


image.png

handleOnBackPressed() 处理逻辑如下:


当回退栈中有记录时,调用popBackStackImmediate(),该方法调用popBackStackImmediate(String name, int id, int flags)


image.png

image.png


代码1处就是处理当前FragmentManager有主导航Fragment时的返回场景。如果主导航Fragment不为空时,交由childManager处理返回。如果childMananger拦截了返回键处理则返回,否则继续让当前FragmentManager处理。具体场景,后文详解。


代码2处 popBackStackState(ArrayList records, ArrayList isRecordPop, String name, int id, int flags)的作用是将回退栈中的FragmentTransaction(BackStackRecord)放到records集合中,以备后用。


image.png

出栈分为4种情况(简单起见,id不考虑了,否则根据排列组合有8中情况)


case name POP_BACK_STACK_INCLUSIVE
case1 null 0
case2 not null 0
case3 not null 1
case4 null 1


POP_BACK_STACK_INCLUSIVE = 1时表示,根据name找到返回栈里面的BackStackRecord,一起出栈。


image.png

假设有回退栈如下。我们来走下四种case。


case->popBackStack(null,0)


image.png

image.pngimage.png

image.png

image.png

image.png

image.png



image.png

代码3处 removeRedundantOperationsAndExecute(mTmpRecords, mTmpIsPop)真正执行出栈操作。最终执行到executeOpsTogether方法。深入理解Navigation架构之Fragment基础一文有详细讲解。


4. setPrimaryNavigationFragment



经过前面那么多的铺垫,终于来到讲解本文主角setPrimaryNavigationFragment了(下文简称:“主导航Fragment”)。前文例子,我们都是基于FragmentActivity平铺Fragment场景讲解的。如果Fragment嵌套Fragment,该如何处理返回栈呢。“主导航Fragment”就是为了解决嵌套Fragment而设计的。前文讲到“Fragment必须依附在NavHostFragment上”,其实就是嵌套Fragment了。


image.png

从上图我们看到有三种角色。HostActivity,HostFragment,Child Fragment(s)。

HostFragment就是通过成为“主导航Fragment”,接管Activity的处理返回操作,并且将返回操作交由ChildFragment(s)去处理。作用可谓“承上启下”。

文字描述始终有点晦涩难懂。上场景图解。


image.png

分两种场景。


Case HostFragment
Case1 不成为主导航Fragment
Case2 成为主导航Fragment

Case1 伪代码如下


image.png

Case2 伪代码如下


image.png


返回场景如下


Case1

image.png

image.png

image.png

image.png

image.png

image.png


相关文章
|
1月前
|
监控 安全 API
使用PaliGemma2构建多模态目标检测系统:从架构设计到性能优化的技术实践指南
本文详细介绍了PaliGemma2模型的微调流程及其在目标检测任务中的应用。PaliGemma2通过整合SigLIP-So400m视觉编码器与Gemma 2系列语言模型,实现了多模态数据的高效处理。文章涵盖了开发环境构建、数据集预处理、模型初始化与配置、数据加载系统实现、模型微调、推理与评估系统以及性能分析与优化策略等内容。特别强调了计算资源优化、训练过程监控和自动化优化流程的重要性,为机器学习工程师和研究人员提供了系统化的技术方案。
171 77
使用PaliGemma2构建多模态目标检测系统:从架构设计到性能优化的技术实践指南
|
1月前
|
机器学习/深度学习 算法 数据可视化
基于深度混合架构的智能量化交易系统研究: 融合SSDA与LSTM自编码器的特征提取与决策优化方法
本文探讨了在量化交易中结合时序特征和静态特征的混合建模方法。通过整合堆叠稀疏降噪自编码器(SSDA)和基于LSTM的自编码器(LSTM-AE),构建了一个能够全面捕捉市场动态特性的交易系统。SSDA通过降噪技术提取股票数据的鲁棒表示,LSTM-AE则专注于捕捉市场的时序依赖关系。系统采用A2C算法进行强化学习,通过多维度的奖励计算机制,实现了在可接受的风险水平下最大化收益的目标。实验结果显示,该系统在不同波动特征的股票上表现出差异化的适应能力,特别是在存在明确市场趋势的情况下,决策准确性较高。
72 5
基于深度混合架构的智能量化交易系统研究: 融合SSDA与LSTM自编码器的特征提取与决策优化方法
|
11天前
|
消息中间件 监控 小程序
电竞陪玩系统架构优化设计,陪玩app如何提升系统稳定性,陪玩小程序平台的测试与监控
电竞陪玩系统架构涵盖前端(React/Vue)、后端(Spring Boot/php)、数据库(MySQL/MongoDB)、实时通信(WebSocket)及其他组件(Redis、RabbitMQ、Nginx)。通过模块化设计、微服务架构和云计算技术优化,提升系统性能与可靠性。同时,加强全面测试、实时监控及故障管理,确保系统稳定运行。
|
1月前
|
机器学习/深度学习 人工智能 并行计算
【AI系统】Kernel 层架构
推理引擎的Kernel层负责执行底层数学运算,如矩阵乘法、卷积等,直接影响推理速度与效率。它与Runtime层紧密配合,通过算法优化、内存布局调整、汇编优化及调度优化等手段,实现高性能计算。Kernel层针对不同硬件(如CPU、GPU)进行特定优化,支持NEON、AVX、CUDA等技术,确保在多种平台上高效运行。
96 32
|
1月前
|
存储 机器学习/深度学习 人工智能
【AI系统】计算图优化架构
本文介绍了推理引擎转换中的图优化模块,涵盖算子融合、布局转换、算子替换及内存优化等技术,旨在提升模型推理效率。计算图优化技术通过减少计算冗余、提高计算效率和减少内存占用,显著改善模型在资源受限设备上的运行表现。文中详细探讨了离线优化模块面临的挑战及解决方案,包括结构冗余、精度冗余、算法冗余和读写冗余的处理方法。此外,文章还介绍了ONNX Runtime的图优化机制及其在实际应用中的实现,展示了如何通过图优化提高模型推理性能的具体示例。
63 4
【AI系统】计算图优化架构
|
28天前
|
机器学习/深度学习 存储 人工智能
基于AI的实时监控系统:技术架构与挑战分析
AI视频监控系统利用计算机视觉和深度学习技术,实现实时分析与智能识别,显著提升高风险场所如监狱的安全性。系统架构包括数据采集、预处理、行为分析、实时决策及数据存储层,涵盖高分辨率视频传输、图像增强、目标检测、异常行为识别等关键技术。面对算法优化、实时性和系统集成等挑战,通过数据增强、边缘计算和模块化设计等方法解决。未来,AI技术的进步将进一步提高监控系统的智能化水平和应对复杂安全挑战的能力。
|
1月前
|
机器学习/深度学习 前端开发 算法
婚恋交友系统平台 相亲交友平台系统 婚恋交友系统APP 婚恋系统源码 婚恋交友平台开发流程 婚恋交友系统架构设计 婚恋交友系统前端/后端开发 婚恋交友系统匹配推荐算法优化
婚恋交友系统平台通过线上互动帮助单身男女找到合适伴侣,提供用户注册、个人资料填写、匹配推荐、实时聊天、社区互动等功能。开发流程包括需求分析、技术选型、系统架构设计、功能实现、测试优化和上线运维。匹配推荐算法优化是核心,通过用户行为数据分析和机器学习提高匹配准确性。
98 3
|
1月前
|
前端开发 搜索推荐 安全
陪玩系统架构设计陪玩系统前后端开发,陪玩前端设计是如何让人眼前一亮的?
陪玩系统的架构设计、前后端开发及前端设计是构建吸引用户、功能完善的平台关键。架构需考虑用户需求、技术选型、安全性等,确保稳定性和扩展性。前端可选用React、Vue或Uniapp,后端用Spring Boot或Django,数据库结合MySQL和MongoDB。功能涵盖用户管理、陪玩者管理、订单处理、智能匹配与通讯。安全性方面采用SSL加密和定期漏洞扫描。前端设计注重美观、易用及个性化推荐,提升用户体验和平台粘性。
62 0
|
1月前
|
监控 Java 数据中心
微服务架构系统稳定性的神器-Hystrix
Hystrix是由Netflix开源的库,主要用于微服务架构中的熔断器模式,防止服务调用失败引发级联故障。它通过监控服务调用的成功和失败率,在失败率达到阈值时触发熔断,阻止后续调用,保护系统稳定。Hystrix具备熔断器、资源隔离、降级机制和实时监控等功能,提升系统的容错性和稳定性。然而,Hystrix也存在性能开销、配置复杂等局限,并已于2018年进入维护模式。
34 0
|
1月前
|
机器学习/深度学习 人工智能 调度
【AI系统】推理引擎架构
本文详细介绍了推理引擎的基本概念、特点、技术挑战及架构设计。推理引擎作为 AI 系统中的关键组件,负责将训练好的模型部署到实际应用中,实现智能决策和自动化处理。文章首先概述了推理引擎的四大特点:轻量、通用、易用和高效,接着探讨了其面临的三大技术挑战:需求复杂性与程序大小的权衡、算力需求与资源碎片化的矛盾、执行效率与模型精度的双重要求。随后,文章深入分析了推理引擎的整体架构,包括优化阶段的模型转换工具、模型压缩、端侧学习等关键技术,以及运行阶段的调度层、执行层等核心组件。最后,通过具体的开发流程示例,展示了如何使用推理引擎进行模型的加载、配置、数据预处理、推理执行及结果后处理。
128 0

热门文章

最新文章