Fragment与ViewModel(MVVM架构)

打印 上一主题 下一主题

主题 871|帖子 871|积分 2613

简介

        在Android应用开发中,Fragment和ViewModel是两个非常重要的概念,它们分别属于架构组件库的一部门,旨在帮助开发者构建更加模块化、健壮且易维护的应用。
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。如许做有以下几个好处:

  • 数据共享:如果多个Fragment需要共享数据,可以将这些数据放在一个共享的ViewModel中。如许,即使Fragment被重建,数据仍然保持不变,而且Fragment之间可以直接访问这些共享数据,无需通过Activity通报。
  • 生命周期解耦:ViewModel不依赖于UI组件的生命周期,因此即使Fragment销毁并重新创建(比如由于设置变更),ViewModel仍然存在,包管了数据的连续性。
  • 简化数据管理:ViewModel负责数据的获取、存储和处置惩罚,而Fragment专注于展示数据和处置惩罚用户交互,这使得代码结构更加清晰,易于维护。
一、开启绑定Binding

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

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

buildFeatures:

  1. android {
  2.     ...
  3.     buildFeatures {
  4.         viewBinding = true // 注意,新版一定要有=
  5.     }
  6. }
复制代码


  • 这是启用ViewBinding的保举方式,特殊是在较新的Android Gradle插件版本中。buildFeatures是一个聚集了各种构建特性的开关,通过在这里设置viewBinding为true,你告诉Gradle在构建时天生ViewBinding类。这些类让你能够以范例安全的方式访问XML布局中的视图,无需手动调用findViewById。
dataBinding:

  1. android {
  2.     ...
  3.     dataBinding {
  4.         enabled = true // 注意,新版一定要有=
  5.     }
  6. }
复制代码


  • 类似地,这是启用DataBinding的方式。通过在dataBinding块内设置enabled为true,你激活了DataBinding特性。DataBinding比ViewBinding更进一步,提供了数据和视图之间的双向绑定本领,允许在布局文件中直接使用数据对象,并支持表达式来处置惩罚数据变革,实现更复杂的UI逻辑。
viewBinding:

  1. android {
  2.     ...
  3.     viewBinding {
  4.         enabled = true // 注意,新版一定要有=
  5.     }
  6. }
复制代码
正确的设置应该遵循上述第一条提到的buildFeatures { viewBinding = true }。实际上保举使用buildFeatures块来设置ViewBinding。选择哪种绑定技术取决于你的项目需求:简单视图绑定用ViewBinding,需要更复杂数据逻辑处置惩罚则使用DataBinding。
二、加载布局

ActivityMain:

        

  1. // 定义MainActivity类,继承自AppCompatActivity,这是Android提供的一个Activity基类,用于兼容旧版设备
  2. public class MainActivity extends AppCompatActivity {
  3.     // 声明一个私有成员变量binding,类型为ActivityMainBinding,用于存储由Data Binding生成的绑定对象
  4.     private ActivityMainBinding binding;
  5.     // 重写onCreate()方法,这是Activity生命周期的第一个回调方法,用于初始化Activity
  6.     @Override
  7.     protected void onCreate(@Nullable Bundle savedInstanceState) {
  8.         super.onCreate(savedInstanceState); // 调用父类的onCreate()方法,执行基本的初始化工作
  9.         // 使用Data Binding的inflate方法从XML布局文件创建一个绑定对象
  10.         // getLayoutInflater()返回LayoutInflater实例,用于将XML布局转换为View对象
  11.         // ActivityMainBinding.inflate()方法将布局文件转换为ActivityMainBinding对象
  12.         binding = ActivityMainBinding.inflate(getLayoutInflater());
  13.         // 设置Activity的内容视图,即将绑定对象的根视图设置为Activity的布局
  14.         // binding.getRoot()返回inflate生成的View对象,即整个布局的根View
  15.         setContentView(binding.getRoot());
  16.     }
  17. }
复制代码
在这个过程中,以下步调发生:

  • 声明Binding对象:在MainActivity类中声明了一个ActivityMainBinding范例的私有变量binding,ActivityMainBinding是Data Binding自动天生的类,用于封装和管理XML布局文件中的全部视图。
  • 加载布局:在onCreate()方法中,起首调用super.onCreate()来执行父类的初始化过程。然后使用ActivityMainBinding.inflate()方法加载布局文件,getLayoutInflater()提供了创建布局的本领。
  • 设置内容视图:调用setContentView()方法,并传入binding.getRoot()返回的根视图,将该视图设置为MainActivity的布局视图。这意味着MainActivity的界面将按照ActivityMainBinding所绑定的XML布局文件来渲染。
通过使用Data Binding,开发者可以直接通过binding对象访问布局文件中的全部视图,而无需调用findViewById()方法,这使得代码更加简便、可读性更强,同时也避免了一些常见的错误,如空指针非常
ViewModel:


  1. // 定义一个继承自ViewModel的类,用于存储界面相关的数据,保证数据在配置变化时不会丢失
  2. public class SyFragmentViewModel extends ViewModel {
  3.     // 声明一个私有成员变量mText,类型为MediatorLiveData<String>,用于存储和分发字符串数据
  4.     private MediatorLiveData<String> mText;
  5.     // 构造函数,初始化mText并设置其初始值
  6.     public SyFragmentViewModel() {
  7.         // 创建并初始化MediatorLiveData实例
  8.         mText = new MediatorLiveData<>();
  9.         // 设置mText的初始值
  10.         mText.setValue("第一个页面");
  11.     }
  12.     // 公共方法,返回mText,允许外部组件观察mText的数据变化
  13.     public LiveData<String> getText() {
  14.         return mText;
  15.     }
  16. }
复制代码
通过上述代码,SyFragmentViewModel可以被Fragment或Activity使用,以观察和相应数据变革,从而实现实时更新UI的结果。
Fragment:


  1. // 定义SyFragment类,继承自Fragment,这是Android中用于构建可重用UI块的类。
  2. public class SyFragment extends Fragment {
  3.     // 声明一个私有成员变量binding,类型为SyActivityBinding。这是Data Binding自动生成的类,
  4.     // 它包含了对SyFragment所使用的XML布局文件中所有View的引用。
  5.     private SyActivityBinding binding;
  6.     // 重写onCreateView()方法,这是Fragment生命周期的一部分,用于创建并返回Fragment的用户界面视图。
  7.     @Nullable
  8.     @Override
  9.     public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
  10.         // 使用Data Binding的inflate方法从XML布局文件创建一个绑定对象。
  11.         // 第一个参数是LayoutInflater,用于将XML布局转换为View对象;
  12.         // 第二个参数是ViewGroup,表示inflate出的View是否应立即附加到该ViewGroup;
  13.         // 第三个参数是一个布尔值,如果为true,inflate出的View将附加到container,否则不会。
  14.         // 这里inflate方法会根据XML布局文件生成相应的View对象,并将这些View对象封装进binding对象中。
  15.         binding = SyActivityBinding.inflate(inflater, container, false);
  16.         // 获取inflate生成的View对象,即整个布局的根View,以便返回给onCreateView()方法。
  17.         View root = binding.getRoot();
  18.         // 从binding中获取TextView的引用,这一步利用了Data Binding的便利性,可以直接通过属性名访问View。
  19.         final TextView textView = binding.textView;
  20.         // 创建并获取SyFragmentViewModel的实例。ViewModelProvider是一个工具类,用于创建和管理ViewModel实例。
  21.         // 这里的this参数告诉ViewModelProvider当前Fragment需要哪个ViewModel。
  22.         SyFragmentViewModel syFragmentViewModel = new ViewModelProvider(this).get(SyFragmentViewModel.class);
  23.         // 观察SyFragmentViewModel中getText()返回的LiveData对象。
  24.         // observe()方法用于注册观察者,getViewLifecycleOwner()确保观察者只在Fragment可见时生效。
  25.         // textView::setText是一种方法引用,表示当LiveData数据改变时,自动调用TextView的setText()方法更新UI。
  26.         syFragmentViewModel.getText().observe(getViewLifecycleOwner(), textView::setText);
  27.         // 返回inflate生成的根View,这将是Fragment的用户界面。
  28.         return root;
  29.     }
  30.     // 重写onDestroy()方法,这是Fragment生命周期的一部分,当Fragment不可见时调用。
  31.     // 这里设置binding为null,有助于回收资源,防止内存泄漏。
  32.     @Override
  33.     public void onDestroy() {
  34.         super.onDestroy();
  35.         binding = null;
  36.     }
  37. }
复制代码
        这段代码展示了如安在一个Fragment中使用Data Binding和ViewModel来构建UI,并相应数据变革。通过使用Data Binding,我们可以更简便地访问布局中的View;通过ViewModel和LiveData,我们可以在数据变革时自动更新UI,同时包管数据在设置变更时的恒久性。
ViewGroup:

        ViewGroup是一个非常重要的概念,它是View体系结构中的底子组件之一,负责构造和管理子View(包罗其他ViewGroup)。简单来说,ViewGroup就是一种特殊的View,它不仅自己可以表现内容,还可以包含多个子View,而且能够控制这些子View的布局方式。
在SyFragment的onCreateView()方法中,ViewGroup重要体现在inflater.inflate()方法的第二个参数——container。这里的container实际上就是一个ViewGroup,它是指定用于容纳由LayoutInflater从XML布局文件中分析出来的View组件的父容器。
当你调用SyActivityBinding.inflate(inflater, container, false)时:


  • inflater是LayoutInflater的实例,它负责读取XML布局文件,并将其转换为实际的View对象。
  • container是ViewGroup的实例,代表了onCreateView()方法中返回的View将要被添加到的父容器。通常情况下,container是Fragment将要附加到的Activity的主布局。
  • false作为第三个参数,意味着从XML布局文件中inflate出来的View不会立即被添加到container中。这是因为Fragment的View应该由FragmentManager来管理,而不是直接由ViewGroup来管理。FragmentManager会在得当的机遇将View添加到container中。
所以,在这个特定的上下文中,ViewGroup的作用重要是作为Fragment视图层次结构的一部门,为Fragment的布局提供一个容器。当Fragment变得可见时,其视图将被FragmentManager添加到指定的ViewGroup(即container)中。
这里,SyActivityBinding.inflate()方法通过LayoutInflater和ViewGroup(container),实现了从XML布局文件到View对象的转换,并通过Data Binding的方式将这些View对象封装进SyActivityBinding对象中,便于后续的代码访问和利用。
三、布局加载比力

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

  1. binding = ActivityMainBinding.inflate(getLayoutInflater());
复制代码

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

  1. 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中代码实现:


  1. public class MainActivity extends AppCompatActivity {
  2.     // 定义一个 ActivityMainBinding 类型的成员变量 binding,
  3.     // ActivityMainBinding 是由 Data Binding 自动生成的类,用于绑定 XML 布局文件中的元素到 Java 代码。
  4.     private ActivityMainBinding binding;
  5.     @Override
  6.     protected void onCreate(@Nullable Bundle savedInstanceState) {
  7.         // 调用父类的 onCreate 方法,这是每个 Activity 的 onCreate 方法都应该做的。
  8.         super.onCreate(savedInstanceState);
  9.         // 使用 Data Binding 的 inflate 方法从 XML 文件加载布局。
  10.         // getLayoutInflater() 返回 LayoutInflater 实例,用于加载布局。
  11.         // ActivityMainBinding.inflate 方法会解析 res/layout/activity_main.xml 文件,
  12.         // 并返回一个 ActivityMainBinding 实例,其中包含布局文件中的所有视图组件。
  13.         binding = ActivityMainBinding.inflate(getLayoutInflater());
  14.         // 设置 Activity 的内容视图。binding.getRoot() 方法返回布局文件中的根视图。
  15.         setContentView(binding.getRoot());
  16.         // 通过 Data Binding 访问 BottomNavigationView 视图,其 ID 在 activity_main.xml 文件中定义。
  17.         BottomNavigationView bottomNavigationView = binding.BottomNavi;
  18.         // 创建 NavController 实例,用于管理应用中的导航。
  19.         // Navigation.findNavController 方法需要传入一个 Context 和一个 View 的 ID,
  20.         // 这里使用 R.id.fragmentContainerView 表示要查找的 NavController 管理的 Fragment 容器。
  21.         NavController navController = Navigation.findNavController(this, R.id.fragmentContainerView);
  22.         // 创建 AppBarConfiguration 实例,用于配置 App Bar 的行为,这里使用默认配置。
  23.         // AppBarConfiguration 的构造函数可以接收多个参数来配置不同的行为,
  24.         // 但在这个例子中,使用了默认的构造函数,没有进行任何配置。
  25.         AppBarConfiguration appBarConfiguration = new AppBarConfiguration.Builder().build();
  26.         // 使用 NavigationUI.setupActionBarWithNavController 方法设置 ActionBar 与 NavController 的关联,
  27.         // 这样 ActionBar 就可以根据 NavController 的状态显示相应的标题和导航项。
  28.         // 第一个参数是当前 Activity,第二个参数是 NavController,第三个参数是 AppBarConfiguration。
  29.         NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration);
  30.         // 使用 NavigationUI.setupWithNavController 方法设置 BottomNavigationView 与 NavController 的关联,
  31.         // 这样 BottomNavigationView 就可以响应 NavController 的变化,显示正确的菜单项。
  32.         // 第一个参数是 BottomNavigationView,第二个参数是 NavController。
  33.         NavigationUI.setupWithNavController(bottomNavigationView, navController);
  34.     }
  35. }
复制代码
最终结果:





免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

汕尾海湾

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表