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
    @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.mfbz.cn/a/747222.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

nacos在k8s上的集群安装实践

目录 概述实践nfs安装使用 k8s持久化nacos安装创建角色部署数据库执行数据库初始化语句部署nacos ingress效果展示 结束 概述 本文主要对 nacos 在k8s上的集群安装 进行说明与实践。主要版本信息&#xff0c;k8s: 1.27.x&#xff0c;nacos: 2.0.3。运行环境为 centos 7.x。 实…

centos 使用证书验证拉取gitee代码 配置

简单记录下过程 按官方网站提示即可 cd ~/.ssh/ #如果没有证书 生成一个 ssh-keygen -t rsa[root萨法是的 .ssh]# ssh-keygen -t rsa Generating public/private rsa key pair. Enter file in which to save the key (/root/.ssh/id_rsa):▽ Enter passphrase (empty for …

logstash配置文件中明文密码加密

1 案例背景 应用配置文件中禁止使用明文密码&#xff0c;需要加密处理 上图中&#xff0c;红框打码位置为es的明文密码&#xff0c;需要对其进行处理 2 创健keystore文件 /rpa/logstash/bin/logstash-keystore --path.settings /rpa/isa/conf/logstash/ create 注&#xff1…

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报错详解…

Okhttp响应Json数据

简介 OkHttp是一个高效、现代的HTTP客户端库&#xff0c;专为Android和Java应用程序设计&#xff0c;用于发送网络请求和处理响应。它支持HTTP/2和SPDY协议&#xff0c;允许连接复用&#xff0c;减少延迟&#xff0c;提高网络效率。OkHttp还处理了常见的网络问题&#xff0c;如…

【目标检测】Yolov8 完整教程 | 检测 | 计算机视觉

学习资源&#xff1a;https://www.youtube.com/watch?vZ-65nqxUdl4 努力的小巴掌 记录计算机视觉学习道路上的所思所得。 1、准备图片images 收集数据网站&#xff1a;OPEN IMAGES 2、准备标签labels 网站&#xff1a;CVAT 有点是&#xff1a;支持直接导出yolo格式的标…

Flutter实现页面间传参

带参跳转 步骤 在router中配置这个路由需要携带的参数,这里的参数是 arguments,注意要用花括号包裹参数名称 在相应组件中实现带参构造函数 在state类中可以直接使用${widget.arguments}来访问到传递的参数 在其他页面中使用Navigator.pushNamed()带参跳转

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

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

BUG cn.bing.com 重定向的次数过多,无法搜索内容

BUG cn.bing.com 重定向的次数过多&#xff0c;无法搜索内容 环境 windows 11 edge浏览器详情 使用Microsoft Edge 必应搜索显示"cn.bing.com"重定向次数过多&#xff0c;无法进行正常的检索功能 解决办法 检查是否开启某些科_学_上_网&#xff08;翻_墙&#xf…

电脑高手推荐:三款超实用软件,让你的电脑如虎添翼!

7Zip 7-Zip是一款免费且开源的文件压缩工具&#xff0c;支持多种文件格式&#xff0c;包括其自带的7z格式、ZIP、GZIP、BZIP2和TAR等。该软件由Igor Pavlov于1999年开发&#xff0c;具有高压缩比的特点。7-Zip不仅可以在Windows操作系统上使用&#xff0c;还可以在Unix-like的操…

做到这九点,工作就无后顾之忧

大家好&#xff0c;今天又跟大家分享一篇&#xff0c;怎么在职场上做到挺起腰杆做事。全文共分9点&#xff0c;尤其最后一点最为重要。篇幅有点长&#xff0c;全文共计三千多字&#xff0c;请耐心看完。 如果您觉得对您有些帮助&#xff0c;点赞收藏关注。谢谢您的支持。 在职场…

LDO芯片手册,实例应用分析

在进行电路设计时LDO是经常用到的&#xff0c;尤其在为芯片&#xff0c;晶振等敏感电路进行供电时应用更多&#xff0c;下面选取一款比较常用的LDO芯片&#xff0c;一起进行更深入的学习。 SGM2036特点简介 SGM2036&#xff0c;圣邦微一款比较常用的LDO芯片手册 可以先大致看…

广州数据中心机房搬迁验收要求

1.验收要求 新机房装修工程全部竣工&#xff0c;各类环境设备安装到位&#xff0c;包括空调、UPS、柴油发电机等设备安装调试完毕&#xff0c;机房接地、防雷、消防系统检验合格&#xff0c;机房综合布线工作完成&#xff0c;机房各项环境指标达标&#xff0c;机房整体通过验收…

MySQL连接

MySQL工具包 MySQL实现简单链接 一 引入工具包 JBDCUtils&#xff0c;无需更改&#xff0c;直接使用即可。 import java.io.IOException; import java.io.InputStream; import java.sql.*; import java.util.Properties;public class JDBCUtil {private static String URL;p…

mapstruct实现各个实体间的类型转换(DTO转BO、BO转Entity)的实践

一、引入 在没有遇见mapstruct的时候&#xff0c;实现各个实体之间的转换&#xff0c;都是手动转换实现的&#xff0c;属性少一带你还好&#xff0c;当属性一多&#xff0c;代码就会变得很冗余&#xff0c;没必要的非逻辑的代码就会加多。。。。 比如&#xff1a; public cl…

Python+Pytest+Yaml+Request+Allure+GitLab+Jenkins接口自动化测试框架概解

PythonPytestYamlAllure整体框架目录&#xff08;源代码请等下篇&#xff09; 框架详解 common:公共方法包 –get_path.py:获取文件路径方法 –logger_util.py:输出日志方法 –parameters_until.py&#xff1a;传参方式方法封装 –requests_util.py&#xff1a;请求方式方法封…

洗地机怎么选择最好?四大洗地机精选放心入手

在当今生活节奏飞快的社会中&#xff0c;人们越来越渴望拥有一款高性能、实用方便的家用洗地机&#xff0c;能够帮助我们节省大量的清洁时间。因为洗地机它是吸尘器的升级版&#xff0c;清洁力比扫地机器人更强&#xff0c;洗地机通过高速旋转的风机&#xff0c;产生超大吸力&a…

无源电压继电器 JDY-1210AW 导轨安装 约瑟JOSEF

系列型号&#xff1a; JDY-1002AW电压继电器&#xff1b;JDY-1002B电压继电器&#xff1b; JDY-1110AW电压继电器&#xff1b;JDY-1110B电压继电器&#xff1b; JDY-1220AW电压继电器&#xff1b;JDY-1220B电压继电器&#xff1b; JDY-1100AW电压继电器&#xff1b;JDY-110…

昇思25天学习打卡营第一天|快速入门

背景 华为组织了昇思25天学习营&#xff0c;从基础开始&#xff0c;提供算力支持&#xff0c;还是体验蛮好的。推荐大家报名参加。 学习内容 今天的内容是快速入门&#xff0c;很简单&#xff0c;当是复习基础内容了。 下载数据集》模型组网》模型训练》保存模型&#xff0c…

mongodb 查询语句学习笔记

基础查询 正则查询 {status: A,$or: [{ qty: { $lt: 30 } }, { item: { $regex: ^p } }] }AND 查询 { "size.h": { $lt: 15 }, "size.uom": "in", status: "D" }OR 查询 { $or: [ { status: "A" }, { qty: { $lt: 30 } …