Fragment与ViewModel(MVVM架构)

简介

        在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@Overrideprotected 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对象,即整个布局的根ViewsetContentView(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@Overridepublic 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,有助于回收资源,防止内存泄漏。@Overridepublic 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;@Overrideprotected 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.mzph.cn/news/861396.shtml

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

相关文章

基于51单片机密码锁—六位密码LCD1602显示

基于51单片机密码锁设计 &#xff08;仿真&#xff0b;程序&#xff0b;设计报告&#xff09; 功能介绍 具体功能&#xff1a; 1.密码为六位数字&#xff0c;有键按下&#xff0c;LCD1602就会显示出字符 “*”&#xff1b; 2.当用户键入正确密码后&#xff0c;再按确认键&a…

是时候系统性的的学习那些开发中必备的软件了!

大家好&#xff0c;我是 王有志&#xff0c;一个分享硬核 Java 技术的金融摸鱼侠&#xff0c;欢迎大家加入 Java 人自己的交流群“共同富裕的 Java 人”。 最近小组内心来了两个实习生&#xff0c;各方面都很不错&#xff0c;基础知识扎实&#xff0c;勤奋好学&#xff08;卷&…

记一次 APK 逆向动静调试 + so 动态链接库分析

0x00 前言&#xff1a; 好久没有做过安卓逆向了&#xff0c;最近重新系统地学习了安卓逆向技术。找到了一道较为典型的逆向分析题来练手&#xff0c;以锻炼动静态分析和动态链接库分析的基本能力。在这里记录基本的分析流程手法。 0x01 逆向分析&#xff1a; 一、使用 Genym…

IPython最简洁方便的Python语法测试工具

前言和需求 相信不少人使用JS时&#xff0c;最常用的快捷键是F12。网页调试&#xff0c;不仅可以调试我们的前端页面&#xff0c;对于多数后端JS程序员来讲&#xff0c;我们有个啥语法不确定了&#xff0c;直接开个网页F12确认一下就行了。甚至写了个方法&#xff0c;不确定对…

springboot + Vue前后端项目(第十九记)

项目实战第十九记 写在前面1. redis安装(windows安装)1.1 获取软件链接地址&#xff1a;1.2 启动redis1.3 测试是否启动成功1.4 通过 Another Redis DeskTop软件可视化查看redis 2. SpringBoot集成redis2.1 引入依赖2.2 注入RedisTemplate2.3 使用redis2.4 redis更新2.5 redis使…

【自然语言处理系列】掌握jieba分词器:从基础到实战,深入文本分析与词云图展示

本文旨在全面介绍jieba分词器的功能与应用&#xff0c;从分词器的基本情况入手&#xff0c;逐步解析全模式与精确模式的不同应用场景。文章进一步指导读者如何通过添加自定义词典优化分词效果&#xff0c;以及如何利用jieba分词器进行关键词抽取和词性标注&#xff0c;为后续的…

美创携手浙江长征职业技术学院,共建智云数据安全大师工作室

6月24日&#xff0c;“美创科技浙江长征职业技术学院智云数据安全大师工作室揭牌暨中国特色学徒制第四期云数据安全和智能运维人才选拔培养启动仪式”在长征职业技术学院隆重举行。 浙江长征职业技术学院计算机与信息技术学院院长梅灿华、计算机与信息技术学院学工办副主任华春…

使用 frida hook Android app

Frida&#xff1a; 一种基于动态插装&#xff08;dynamic instrumentation&#xff09;技术的工具包&#xff0c;它主要是为测试人员、开发人员和逆向工程爱好者创建&#xff0c;在目标程序运行时&#xff0c;允许用户将 JavaScript代码注入其中&#xff0c;实现动态修改和调试…

ONLYOFFICE8.1版本桌面编辑器的测评

首先我们先出示一下我们所测评官网的链接&#xff1a; ONLYOFFICE官网链接&#xff1a;ONLYOFFICE - 企业在线办公应用软件 | ONLYOFFICE 我们这款ONLYOFFICE8.1版本有这一下优点 1.解决PDF痛点 ONLYOFFICE在PDF编辑方面支持高亮显示、下划线和删除线、添加批注等功能&#…

【2024最新版】Eclipse安装配置全攻略:图文详解

目录 1. Eclipse介绍1.1 背景1.2 主要特点和功能1.3 版本发布1.4 优势与劣势 2. 下载Eclipse3. 安装Eclipse4. 启动Eclipse 1. Eclipse介绍 Eclipse是一个开源的、基于Java的可扩展开发平台&#xff0c;主要用于Java开发者&#xff0c;但也支持其他语言如C/C、PHP、Python等。…

【PWN · TcachebinAttack | UAF】[2024CISCN · 华中赛区] note

一道简单的tcache劫持 一、题目 二、思路 存在UAF&#xff0c;libc版本2.31&#xff0c;经典菜单题 1.通过unsorted-bin-attack来leak-libc 2.通过uaf打tcache-bin-attack劫持__free_hook实现getshell 三、EXP from pwn import * context(archamd64,log_leveldebug)ioproce…

ansible自动化运维,(2)ansible-playbook

三种常见的数据格式&#xff1a; XML&#xff1a;可扩展标记语言&#xff0c;用于数据交换和配置 JSON&#xff1a;对象标记法&#xff0c;主要用来数据交换或配置&#xff0c;不支持注释 YAML&#xff1a;不是一种标记语言&#xff0c;主要用来配置&#xff0c;大小写敏感&…

科技未来·无限可能“2024世亚智博会”

随着科技的飞速发展&#xff0c;人类社会正以前所未有的速度迈向一个全新的时代。科学技术作为第一生产力&#xff0c;不仅极大地推动了经济和社会的发展&#xff0c;更在不断地改变着我们的生活方式和思维方式。特别是在人工智能、物联网等前沿科技领域&#xff0c;其创新和应…

【ZYNQ】VDMA 的介绍

AXI VDMA 是 Xilinx 官方提供的高带宽视频 DMA IP&#xff0c;用于实现 AXI4-Stream 视频数据流与 AXI4 接口数据的转换&#xff0c;同时提供帧缓存与帧同步控制功能。本文主要介绍 AXI VDMA 的基本结构与原理&#xff0c;并简要介绍 VDMA 的配置与使用方法。 目录 1 VDMA 简介…

egg代码生成器

今天给大家分享一下egg的代码生成器&#xff0c;这个其实原理很简单&#xff0c;说白了就是用到了nodejs的一个文件io的操作&#xff0c;通过一系列配置参数解析然后生成一个很长的字符串&#xff0c;写入到文件中&#xff0c;最后导出到我们指定的文件夹。 前提概要 为什么我…

web前端——VUE

1.什么是框架&#xff1f; ①概述 框架结构就是基本功能&#xff0c;把很多基础功能已经实现了、封装了。在基础语言之上&#xff0c;对各种基础功能进行封装&#xff0c;方便开发者&#xff0c;提高开发效率 ②前端框架 javaScript是原生的 vue.js&#xff1a; 是一个js框架&…

最新解决docker镜像无法下载问题

1.增加或修改daemon.json文件 ​ cd /etc/dockervi daemon.json{ "registry-mirrors": [ "https://docker.m.daocloud.io" ] }2.重启docker服务 sudo systemctl daemon-reload sudo systemctl restart docker 3.验证 下载https://txodoo.cn/blog/11/d…

双指针dd d df f

像二分这样的算法&#xff0c;我们甚至可以不用管&#xff0c;直接在问题空间之内搜索&#xff0c;但是双指针也非常好用&#xff0c;帮助我们来减少枚举对象&#xff0c;我们来总结一下这经典的三个题目&#xff1a; 最长上升不重复子序列活动 - AcWings 首先一定要写…

LabVIEW电路板故障诊断系统

基于LabVIEW软件开发的电路板故障诊断系统&#xff0c;涵盖功能测试、性能测试和通讯测试等多个方面。系统集成了多种硬件设备&#xff0c;包括NI PXI-1033机箱、NI PXI-4071数字万用表、NI PXI-4130电源模块、NI PXI-8512 CAN模块等&#xff0c;通过模块化设计实现了对电路板的…

shell中的函数

统计家目录下.c文件的个数 终端输入一个.sh文件&#xff0c;判断文件是否由可执行权限&#xff0c;如果有可执行权限运行脚本&#xff0c;没有可执行权限添加可执行权限后&#xff0c;再运行脚本 写一个函数&#xff0c;输出当前用户uid和gid&#xff0c;并使用变量接收结果 终…