Fragment与ViewModel(MVVM架构)

news2025/2/23 19:32:51

简介

        在Android应用开发中,FragmentViewModel是两个非常重要的概念,它们分别属于架构组件库的一部分,旨在帮助开发者构建更加模块化、健壮且易维护的应用。

Fragment

  Fragment是Android系统提供的一种可重用的UI组件,它能够作为活动(Activity)的一部分,具有自己的生命周期,并且可以在多个Activity中使用。Fragment的设计初衷是为了支持更灵活的屏幕布局,特别是在需要适配不同屏幕尺寸和方向时。通过组合多个Fragment,开发者可以创建丰富的用户界面,并且每个Fragment都可以独立地处理用户输入、保存状态等,从而提高代码的复用性和模块化。

ViewModel

  ViewModel是Android架构组件库中的一个核心类,用于存储和管理UI相关的数据。它的主要目的分离视图(View)和数据,使得数据能够在配置变更(如屏幕旋转)时保持避免了因Activity或Fragment重建导致的数据丢失问题。ViewModel的生命周期独立于UI控制器(Activity或Fragment),确保了数据的持久性。此外,ViewModel还可以与LiveData等组件结合使用,实现数据变化的自动通知,简化了UI更新的逻辑

Fragment与ViewModel的协同工作

在实际开发中,为了实现Fragment的数据持久化和解耦,通常会为Fragment关联一个ViewModel。这样做有以下几个好处:

  1. 数据共享:如果多个Fragment需要共享数据,可以将这些数据放在一个共享的ViewModel中。这样,即使Fragment被重建,数据仍然保持不变,而且Fragment之间可以直接访问这些共享数据,无需通过Activity传递。

  2. 生命周期解耦:ViewModel不依赖于UI组件的生命周期,因此即使Fragment销毁并重新创建(比如由于配置变更),ViewModel仍然存在,保证了数据的连续性。

  3. 简化数据管理:ViewModel负责数据的获取、存储和处理,而Fragment专注于展示数据和处理用户交互,这使得代码结构更加清晰,易于维护。

一、开启绑定Binding

Step 1: 打开build.gradle(Module级别)文件。

Step 2:android闭包内,确保buildFeatures块存在,然后添加viewBinding属性并设为true

buildFeatures:

android {
    ...
    buildFeatures {
        viewBinding = true // 注意,新版一定要有=
    }
}
  • 这是启用ViewBinding的推荐方式,特别是在较新的Android Gradle插件版本中。buildFeatures是一个集合了各种构建特性的开关,通过在这里设置viewBindingtrue,你告诉Gradle在构建时生成ViewBinding类。这些类让你能够以类型安全的方式访问XML布局中的视图,无需手动调用findViewById

dataBinding:

android {
    ...
    dataBinding {
        enabled = true // 注意,新版一定要有=
    }
}
  • 类似地,这是启用DataBinding的方式。通过在dataBinding块内设置enabledtrue,你激活了DataBinding特性。DataBinding比ViewBinding更进一步,提供了数据和视图之间的双向绑定能力,允许在布局文件中直接使用数据对象,并支持表达式来处理数据变化,实现更复杂的UI逻辑。

viewBinding:

android {
    ...
    viewBinding {
        enabled = true // 注意,新版一定要有=
    }
}

正确的配置应该遵循上述第一条提到的buildFeatures { viewBinding = true }。实际上推荐使用buildFeatures块来配置ViewBinding。选择哪种绑定技术取决于你的项目需求:简单视图绑定用ViewBinding,需要更复杂数据逻辑处理则使用DataBinding。

二、加载布局

ActivityMain:

        

// 定义MainActivity类,继承自AppCompatActivity,这是Android提供的一个Activity基类,用于兼容旧版设备
public class MainActivity extends AppCompatActivity {

    // 声明一个私有成员变量binding,类型为ActivityMainBinding,用于存储由Data Binding生成的绑定对象
    private ActivityMainBinding binding;

    // 重写onCreate()方法,这是Activity生命周期的第一个回调方法,用于初始化Activity
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState); // 调用父类的onCreate()方法,执行基本的初始化工作

        // 使用Data Binding的inflate方法从XML布局文件创建一个绑定对象
        // getLayoutInflater()返回LayoutInflater实例,用于将XML布局转换为View对象
        // ActivityMainBinding.inflate()方法将布局文件转换为ActivityMainBinding对象
        binding = ActivityMainBinding.inflate(getLayoutInflater());

        // 设置Activity的内容视图,即将绑定对象的根视图设置为Activity的布局
        // binding.getRoot()返回inflate生成的View对象,即整个布局的根View
        setContentView(binding.getRoot());
    }
}

在这个过程中,以下步骤发生:

  1. 声明Binding对象:在MainActivity类中声明了一个ActivityMainBinding类型的私有变量bindingActivityMainBinding是Data Binding自动生成的类,用于封装和管理XML布局文件中的所有视图。

  2. 加载布局:在onCreate()方法中,首先调用super.onCreate()来执行父类的初始化过程。然后使用ActivityMainBinding.inflate()方法加载布局文件,getLayoutInflater()提供了创建布局的能力。

  3. 设置内容视图:调用setContentView()方法,并传入binding.getRoot()返回的根视图,将该视图设置为MainActivity的布局视图。这意味着MainActivity的界面将按照ActivityMainBinding所绑定的XML布局文件来渲染。

通过使用Data Binding,开发者可以直接通过binding对象访问布局文件中的所有视图,而无需调用findViewById()方法,这使得代码更加简洁、可读性更强,同时也避免了一些常见的错误,如空指针异常

ViewModel:

// 定义一个继承自ViewModel的类,用于存储界面相关的数据,保证数据在配置变化时不会丢失
public class SyFragmentViewModel extends ViewModel {

    // 声明一个私有成员变量mText,类型为MediatorLiveData<String>,用于存储和分发字符串数据
    private MediatorLiveData<String> mText;

    // 构造函数,初始化mText并设置其初始值
    public SyFragmentViewModel() {
        // 创建并初始化MediatorLiveData实例
        mText = new MediatorLiveData<>();
        // 设置mText的初始值
        mText.setValue("第一个页面");
    }

    // 公共方法,返回mText,允许外部组件观察mText的数据变化
    public LiveData<String> getText() {
        return mText;
    }
}

通过上述代码,SyFragmentViewModel可以被FragmentActivity使用,以观察和响应数据变化,从而实现实时更新UI的效果。

Fragment:

// 定义SyFragment类,继承自Fragment,这是Android中用于构建可重用UI块的类。
public class SyFragment extends Fragment {

    // 声明一个私有成员变量binding,类型为SyActivityBinding。这是Data Binding自动生成的类,
    // 它包含了对SyFragment所使用的XML布局文件中所有View的引用。
    private SyActivityBinding binding;

    // 重写onCreateView()方法,这是Fragment生命周期的一部分,用于创建并返回Fragment的用户界面视图。
    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        // 使用Data Binding的inflate方法从XML布局文件创建一个绑定对象。
        // 第一个参数是LayoutInflater,用于将XML布局转换为View对象;
        // 第二个参数是ViewGroup,表示inflate出的View是否应立即附加到该ViewGroup;
        // 第三个参数是一个布尔值,如果为true,inflate出的View将附加到container,否则不会。
        // 这里inflate方法会根据XML布局文件生成相应的View对象,并将这些View对象封装进binding对象中。
        binding = SyActivityBinding.inflate(inflater, container, false);

        // 获取inflate生成的View对象,即整个布局的根View,以便返回给onCreateView()方法。
        View root = binding.getRoot();

        // 从binding中获取TextView的引用,这一步利用了Data Binding的便利性,可以直接通过属性名访问View。
        final TextView textView = binding.textView;

        // 创建并获取SyFragmentViewModel的实例。ViewModelProvider是一个工具类,用于创建和管理ViewModel实例。
        // 这里的this参数告诉ViewModelProvider当前Fragment需要哪个ViewModel。
        SyFragmentViewModel syFragmentViewModel = new ViewModelProvider(this).get(SyFragmentViewModel.class);

        // 观察SyFragmentViewModel中getText()返回的LiveData对象。
        // observe()方法用于注册观察者,getViewLifecycleOwner()确保观察者只在Fragment可见时生效。
        // textView::setText是一种方法引用,表示当LiveData数据改变时,自动调用TextView的setText()方法更新UI。
        syFragmentViewModel.getText().observe(getViewLifecycleOwner(), textView::setText);

        // 返回inflate生成的根View,这将是Fragment的用户界面。
        return root;
    }

    // 重写onDestroy()方法,这是Fragment生命周期的一部分,当Fragment不可见时调用。
    // 这里设置binding为null,有助于回收资源,防止内存泄漏。
    @Override
    public void onDestroy() {
        super.onDestroy();
        binding = null;
    }
}

        这段代码展示了如何在一个Fragment中使用Data Binding和ViewModel来构建UI,并响应数据变化。通过使用Data Binding,我们可以更简洁地访问布局中的View;通过ViewModel和LiveData,我们可以在数据变化时自动更新UI,同时保证数据在配置变更时的持久性。

ViewGroup:

        ViewGroup是一个非常重要的概念,它是View体系结构中的基础组件之一,负责组织和管理子View(包括其他ViewGroup)。简单来说,ViewGroup就是一种特殊的View,它不仅自己可以显示内容,还可以包含多个子View,并且能够控制这些子View的布局方式。

SyFragmentonCreateView()方法中,ViewGroup主要体现在inflater.inflate()方法的第二个参数——container。这里的container实际上就是一个ViewGroup,它是指定用于容纳由LayoutInflater从XML布局文件中解析出来的View组件的父容器。

当你调用SyActivityBinding.inflate(inflater, container, false)时:

  • inflaterLayoutInflater的实例,它负责读取XML布局文件,并将其转换为实际的View对象。
  • containerViewGroup的实例,代表了onCreateView()方法中返回的View将要被添加到的父容器。通常情况下,containerFragment将要附加到的Activity的主布局。
  • false作为第三个参数,意味着从XML布局文件中inflate出来的View不会立即被添加到container中。这是因为FragmentView应该由FragmentManager来管理,而不是直接由ViewGroup来管理。FragmentManager会在适当的时机将View添加到container中。

所以,在这个特定的上下文中,ViewGroup的作用主要是作为Fragment视图层次结构的一部分,为Fragment的布局提供一个容器。当Fragment变得可见时,其视图将被FragmentManager添加到指定的ViewGroup(即container)中。

这里,SyActivityBinding.inflate()方法通过LayoutInflaterViewGroupcontainer),实现了从XML布局文件到View对象的转换,并通过Data Binding的方式将这些View对象封装进SyActivityBinding对象中,便于后续的代码访问和操作。

三、布局加载比较

        binding = ActivityMainBinding.inflate(getLayoutInflater());binding = YourActivityBinding.inflate(inflater, container, false); 都使用了 Android 的 Data Binding 库来从 XML 布局文件生成对应的 Java 对象,但它们之间存在一些关键区别,主要在于 inflate 方法的调用方式和参数上。

第一种情况:

binding = ActivityMainBinding.inflate(getLayoutInflater());

这里使用的是 ActivityMainBinding 类的 inflate 方法,这个方法不需要额外的容器参数。它直接使用 getLayoutInflater() 来获取 LayoutInflater 实例,然后调用 inflate 方法生成布局。这种情况下,inflate 方法会自动找到一个合适的根视图,并且返回一个 ActivityMainBinding 类型的对象,该对象包含了布局中的所有 View。

第二种情况:

binding = YourActivityBinding.inflate(inflater, container, false);

这个版本的 inflate 方法接收三个参数:

  • inflater: 这是一个 LayoutInflater 实例,通常从父视图或者 Activity 中获取。
  • container: 这是一个可选的父视图容器,如果你想要将这个布局添加到某个已存在的 View 组中时,你需要提供这个容器。如果布局是要作为独立的视图,则可以忽略此参数。
  • attachToRoot: 这个布尔值参数决定了是否将生成的布局视图自动添加到 container 参数指定的容器中。如果设置为 false,则不会自动添加;如果设置为 true,则会自动添加到 container 中。

总结:

  • 如果你的布局是要直接设置为 Activity 的根布局,通常使用第一种方法,因为不需要考虑容器问题。
  • 如果你的布局是要作为子布局添加到某个容器中(比如在 Fragment 或者自定义 View 中),那么你应该使用第二种方法,并且要确保 attachToRoot 参数设置正确,以便于控制布局是否应该被自动添加到容器中。

在大多数情况下,Activity 的布局会直接设置为 Activity 的根视图,因此第一种情况更为常见。然而,在更复杂的场景下,例如在 Fragment 中使用 Data Binding,第二种情况则更为适用。

四、navigation

navigation创建

布局加载

代码完善:

五、menu菜单

menu创建:

Vector图标:

        new创建:

        颜色、名称等设定:

        

        finsh完成:

添加item项:

        代码完善:

切记一定要与navigation的xml代码中fragment的id一致

六、导航实现

BottomNavigationView:

fragment:

        一定要将NavHostFragment改fragment

activity中代码实现:

public class MainActivity extends AppCompatActivity {
    // 定义一个 ActivityMainBinding 类型的成员变量 binding,
    // ActivityMainBinding 是由 Data Binding 自动生成的类,用于绑定 XML 布局文件中的元素到 Java 代码。
    private ActivityMainBinding binding;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        // 调用父类的 onCreate 方法,这是每个 Activity 的 onCreate 方法都应该做的。
        super.onCreate(savedInstanceState);

        // 使用 Data Binding 的 inflate 方法从 XML 文件加载布局。
        // getLayoutInflater() 返回 LayoutInflater 实例,用于加载布局。
        // ActivityMainBinding.inflate 方法会解析 res/layout/activity_main.xml 文件,
        // 并返回一个 ActivityMainBinding 实例,其中包含布局文件中的所有视图组件。
        binding = ActivityMainBinding.inflate(getLayoutInflater());

        // 设置 Activity 的内容视图。binding.getRoot() 方法返回布局文件中的根视图。
        setContentView(binding.getRoot());

        // 通过 Data Binding 访问 BottomNavigationView 视图,其 ID 在 activity_main.xml 文件中定义。
        BottomNavigationView bottomNavigationView = binding.BottomNavi;

        // 创建 NavController 实例,用于管理应用中的导航。
        // Navigation.findNavController 方法需要传入一个 Context 和一个 View 的 ID,
        // 这里使用 R.id.fragmentContainerView 表示要查找的 NavController 管理的 Fragment 容器。
        NavController navController = Navigation.findNavController(this, R.id.fragmentContainerView);

        // 创建 AppBarConfiguration 实例,用于配置 App Bar 的行为,这里使用默认配置。
        // AppBarConfiguration 的构造函数可以接收多个参数来配置不同的行为,
        // 但在这个例子中,使用了默认的构造函数,没有进行任何配置。
        AppBarConfiguration appBarConfiguration = new AppBarConfiguration.Builder().build();

        // 使用 NavigationUI.setupActionBarWithNavController 方法设置 ActionBar 与 NavController 的关联,
        // 这样 ActionBar 就可以根据 NavController 的状态显示相应的标题和导航项。
        // 第一个参数是当前 Activity,第二个参数是 NavController,第三个参数是 AppBarConfiguration。
        NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration);

        // 使用 NavigationUI.setupWithNavController 方法设置 BottomNavigationView 与 NavController 的关联,
        // 这样 BottomNavigationView 就可以响应 NavController 的变化,显示正确的菜单项。
        // 第一个参数是 BottomNavigationView,第二个参数是 NavController。
        NavigationUI.setupWithNavController(bottomNavigationView, navController);
    }
}

最终效果:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1866452.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【第14章】探索新技术:如何自学SD3模型(找官方资料/精读/下载/安装/3款工作流/效果测试)ComfyUI基础入门教程

近期,也就是2024年6月12日,StabilityAI开源了最新的SD3模型的2B版本,而神奇的是,ComfyUI早在6月11号就已经适配了SD3!相比之下,SD WebUI 的更新速度却远远落后... 所以,如果想要尝试一些AI绘画领域的新技术,ComfyUI是一个非常值得投入时间学习的工具。 这节课,我们就…

Ascend基于自定义算子工程的算子开发

环境准备 见https://gitee.com/zaj1414904389/ascend-tutorial.git 工程创建 CANN软件包中提供了工程创建工具msopgen&#xff0c;开发者可以输入算子原型定义文件生成Ascend C算子开发工程 [{"op": "AddCustom","input_desc": [{"name…

2024全网最全面及最新且最为详细的网络安全技巧四 之 sql注入以及mysql绕过技巧 (2)———— 作者:LJS

目录 4.5 DNS记录类型介绍(A记录、MX记录、NS记录等&#xff0c;TXT&#xff0c;CNAME&#xff0c;PTR) 4.5.1 DNS 4.5.2 A记录 4.5.3NS记录 4.5.4 MX记录 4.5.5 CNAME记录 4.5.6 TXT记录 4.5.7 泛域名与泛解析 4.5.8域名绑定 4.5.9 域名转向 4.6 Mysql报错注入之floor报错详解…

基于Java影院管理系统设计和实现(源码+LW+调试文档+讲解等)

&#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN作者、博客专家、全栈领域优质创作者&#xff0c;博客之星、平台优质作者、专注于Java、小程序技术领域和毕业项目实战✌&#x1f497; &#x1f31f;文末获取源码数据库&#x1f31f;感兴趣的可以先收藏起来&#xff0c;还…

若依框架自定义左侧导航栏图标,并变色

若依框架中&#xff0c;有时候设计图跟若依框架自带的图标不一样&#xff0c;需要替换掉&#xff0c;问题来了&#xff0c;怎么替换&#xff0c;并变色&#xff1f; 1、设计师给的图标的路径必须是合并的&#xff0c;非多个路径&#xff0c;这样我们下载下来的svg图才有只有一个…

msvcr110.dll丢失的解决方法,亲测有效的几种解决方法

最近&#xff0c;我在启动一个程序时&#xff0c;系统突然弹出一个错误提示&#xff0c;告诉我电脑缺失了一个名为msvcr110.dll的文件。这让我感到非常困惑&#xff0c;因为我之前从未遇到过这样的问题。经过一番搜索和尝试&#xff0c;我总结了5种靠谱的解决方法。下面分享给大…

平凉小果子,平凡中的惊艳味道

平凉美食小果子&#xff0c;这看似平凡的名字背后&#xff0c;藏着无数平凉人的美好回忆。它不仅仅是一种食物&#xff0c;更是一种情感的寄托&#xff0c;一种文化的传承。小果子的制作过程看似简单&#xff0c;实则蕴含着深厚的功夫。选用优质的面粉作为主要原料&#xff0c;…

vue3-openlayers 要素聚合(cluster)、icon聚合

本篇介绍一下使用vue3-openlayers 要素聚合&#xff08;cluster&#xff09;&#xff0c;icon聚合 1 需求 要素聚合&#xff08;cluster&#xff09;&#xff0c;icon聚合 2 分析 使用ol-source-cluster 4 实现 <template><ol-map:loadTilesWhileAnimating"…

Redis数据库(五):Redis数据库基本特性

这一节我们来介绍如何使用C语言的库来操作Redis数据库。 目录 一、hiredis的安装 1.1 下载源码 1.2 解压 1.3 进入hiredis路径下 1.4 利用makefile文件进行编译 二、接口介绍 三、C程序操作Redis代码 四、redis.conf配置文件详解 五、Redis的持久化 5.1 RDB &#x…

优思学院|精益生产3大特征、5个步骤、8大浪费、10大工具

前言 精益生产作为一种先进的生产管理理念&#xff0c;起源于丰田汽车公司的生产方式&#xff0c;其核心在于消除浪费、优化流程&#xff0c;以最少的投入获取最大的产出。本文将详细解析精益生产的三大特征、五个步骤、八大浪费和十大工具&#xff0c;帮助读者深入理解这一理…

【java计算机毕设】学生作业管理系统java MySQL ssm JSP maven项目源代码+文档

1项目功能 【java计算机毕设】学生作业管理系统java MySQL ssm JSP maven 项目设计源代码 文档 期末小组作业 2项目介绍 系统功能&#xff1a; 学生作业管理系统包括管理员、小管理员、教师、学生四种角色。 管理员功能包括个人中心模块用于修改个人信息和密码、管理员管理、学…

DWC USB2.0协议学习2--架构介绍

目录 1 系统级架构 1.1 DWC_otg PMU模块 1.2 DWC_otg层次结构框图 1.3 DWC_otg功能模块框图 1.4 USB Host体系结构 1.4.1 发送FIFO 1.4.2 接收FIFO 1.5 USB Device体系结构 1.5.1专用发送FIFO 1.5.2 单个接收FIFO 2 DWC_otg_core架构 2.1 AHB总线接口单元(BIU) 2.2…

vue封装原生table表格方法

适用场景&#xff1a;有若干个表格&#xff0c;前面几列格式不一致&#xff0c;但是后面几列格式皆为占一个单元格&#xff0c;所以需要封装表格&#xff0c;表格元素自动根据数据结构生成即可&#xff1b;并且用户可新增列数据。 分类&#xff1a; 固定数据部分 就是根据数据…

合合信息智能文档抽取:赋能不良资产管理行业的数字化转型

官.网地址&#xff1a;合合TextIn - 合合信息旗下OCR云服务产品 随着数字化浪潮的汹涌澎湃&#xff0c;全球各行各业正经历着前所未有的变革。人工智能技术的快速发展&#xff0c;以其独特的创新能力和应用潜力&#xff0c;正在深刻地改变着业务模式&#xff0c;推动产业效率的…

【AIGC】AI技术兴起,设计师要大量失业了吗?

一、前言 随着技术的不断迭代&#xff0c;AIGC 能力的可控性得到了进一步提升&#xff0c;可应用的场景也越来越多&#xff0c;在文本、图像、视频等多个领域都有了广泛应用。 用户已经可以用自然语言来与 AI 工具进行交互&#xff0c;革新传统办公方式&#xff0c;工作任务可…

【Python datetime模块精讲】:时间旅行者的日志,精准操控日期与时间

文章目录 前言一、datetime模块简介二、常用类和方法三、date类四、time类五、datetime类六、timedelta类七、常用的函数和属性八、代码及其演示 前言 Python的datetime模块提供了日期和时间的类&#xff0c;用于处理日期和时间的算术运算。这个模块包括date、time、datetime和…

通过命令行配置调整KVM的虚拟网络

正文共&#xff1a;1234 字 20 图&#xff0c;预估阅读时间&#xff1a;2 分钟 在上篇文章中&#xff08;最小化安装的CentOS7部署KVM虚拟机&#xff09;&#xff0c;我们介绍了如何在最小化安装的CentOS 7系统中部署KVM组件和相关软件包。因为没有GUI图形界面&#xff0c;我们…

【Java Web】XML格式文件

目录 一、XML是什么 二、常见配置文件类型 *.properties类型&#xff1a; *.xml类型&#xff1a; 三、DOM4J读取xml配置文件 3.1 DOM4J的使用步骤 3.2 DOM4J的API介绍 一、XML是什么 XML即可扩展的标记语言&#xff0c;由标记语言可知其基本语法和HTML一样都是由标签构成的文件…

深度之眼(二十六)——神经网络基础知识(一)

文章目录 一、前言二、神经网络与多层感知机2.1 人工神经元2.2 人工神经网络2.3 多层感知机2.4 激活函数 一、前言 看了下课程安排&#xff0c;自己还是没安排好&#xff0c;刚刚捋清了一下思路。 基础&#xff1a;python、数理 认识&#xff1a;神经网络基础、opencv基础、py…