Fragment与ViewModel(MVVM架构)
简介
在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:
android {...buildFeatures {viewBinding = true // 注意,新版一定要有=}
}
- 这是启用ViewBinding的推荐方式,特别是在较新的Android Gradle插件版本中。
buildFeatures是一个集合了各种构建特性的开关,通过在这里设置viewBinding为true,你告诉Gradle在构建时生成ViewBinding类。这些类让你能够以类型安全的方式访问XML布局中的视图,无需手动调用findViewById。
dataBinding:
android {...dataBinding {enabled = true // 注意,新版一定要有=}
}
- 类似地,这是启用DataBinding的方式。通过在
dataBinding块内设置enabled为true,你激活了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());}
}
在这个过程中,以下步骤发生:
-
声明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:

// 定义一个继承自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可以被Fragment或Activity使用,以观察和响应数据变化,从而实现实时更新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的布局方式。
在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 方法的调用方式和参数上。
第一种情况:
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);}
}
最终效果:

相关文章:
Fragment与ViewModel(MVVM架构)
简介 在Android应用开发中,Fragment和ViewModel是两个非常重要的概念,它们分别属于架构组件库的一部分,旨在帮助开发者构建更加模块化、健壮且易维护的应用。 Fragment Fragment是Android系统提供的一种可重用的UI组件,它能够作为…...
Linux开发讲课16--- 【内存管理】页表映射基础知识2
ARM32页表和Linux页表那些奇葩的地方 ARM32硬件页表中PGD页目录项PGD是从20位开始的,但是为何头文件定义是从21位开始? 历史原因:Linux最初是基于x86的体系结构设计的,因此Linux内核很多的头文件的定义都是基于x86的,…...
uniapp地图点击获取位置
主页面 <view class"right-content" click.stop"kilometer(item)"><view class"km">{{item.distance||0}}km</view><image src"../../static/map.png" mode""style"width: 32rpx; height: 32rpx…...
Unity程序开发:1.基本概念及操作
1. 基本概念与操作 Unity 是一个功能强大的游戏开发引擎,广泛用于创建2D和3D游戏。要开始开发游戏,了解游戏对象和组件的基本概念是必不可少的。 游戏对象与组件 什么是游戏对象(GameObject) 在 Unity 中,游戏对象…...
前端新手小白的第一个AI全栈项目---AI聊天室
前言 ok,大家好。- ̗̀(๑ᵔ⌔ᵔ๑)最近也是想做自己的第一个前后端分离的项目,刚好最近学了一点AI接口的实现。想着用接口做一个自己的ai聊天室并且尝试一下全栈式开发。中间真的解决了很多问题,也是成功之后也是想要将实现过程分享一下&a…...
金升阳电源被制裁,广州顶源电源模块可以完美替换
广州顶源电子科技股份有限公司,座落于国家高新技术开发区---广州科学城,是一家集研发、生产、销售及服务于一体的DC-DC,AC-DC电源的生产厂家。 公司通过了IATF16949汽车认证及ISO9001:2015质量管理体系认证。拥有专家级研发团队,产品研发经过…...
《数据赋能:一本书讲透数字化营销与运营》—— 从正确的数据观开始
基于数据打通的“全链路”营销是当下的“时髦”,应用它的前提是什么?深度营销和运营的关键数据如何获得?如何利用数据进行更精准的营销投放?如何利用数据优化投放的效果?如何促进消费者的转化,以及激活留存…...
JDK 24:Leyden
Project Leyden 发布了其首个早期版本(24-leyden2-8 2024/6/20)。初始版本专注于缩短 Java 应用程序的启动时间。 1.特点 提前编译 Java 方法,以便在应用程序在生产运行中启动时立即本地执行它们;提前解析常量池条目可以让 AOT 编译器生成更好的代码&a…...
对于图片转3d人脸方面的研究
1.一个开源的可以运行的项目(face3d/README.md at master yfeng95/face3d GitHub) 在配置好环境后,让我们一个一个py文件运行它(我将给出中文注释) 1)1_pipeline.py 将一个3d头像的mat文件转换为jpg…...
.NET C# 八股文 代码阅读(一)
.NET C# 八股文 代码阅读(一) 目录 .NET C# 八股文 代码阅读(一)1 两种获10000个数的方式,哪种效率更高?为什么?2 请说出以下代码AB谁先打印,AB打印的值分别为多少?3 关于…...
C++用Crow实现一个简单的Web程序,实现动态页面,向页面中输入数据并展示
Crow是一个轻量级、快速的C微框架,用于构建Web应用程序和RESTful API。 将处理前端页面的POST请求以添加数据的逻辑添加到 /submit 路由中,并添加了一个新的路由 / 用于返回包含输入框、按钮和表格的完整页面。当用户向表格添加数据时,JavaS…...
南信大尹志聪教授为一作在顶级综合性期刊《Natl. Sci. Rev.》发文:传统梅雨停摆,江南缘何不再多烟雨?
文章简介 论文名称:Traditional Meiyu–Baiu has been suspended by global warming 第一作者及单位:尹志聪(教授|南京信息工程大学大气科学学院) 通讯作者及单位:王会军(院士|南京信息工程大学大气科学学院) 文章发…...
程序员如何用ChatGPT解决常见编程问题:实例解析
引言 在现代编程的世界中,技术进步日新月异,程序员们面临着各种各样的挑战和问题。解决这些问题的过程中,找到合适的工具至关重要。ChatGPT作为一种先进的人工智能语言模型,能够帮助程序员迅速、高效地解决常见的编程问题。本文将…...
初识 SpringMVC,运行配置第一个Spring MVC 程序
1. 初识 SpringMVC,运行配置第一个Spring MVC 程序 文章目录 1. 初识 SpringMVC,运行配置第一个Spring MVC 程序1.1 什么是 MVC 2. Spring MVC 概述2.1 Spring MVC 的作用: 3. 运行配置第一个 Spring MVC 程序3.1 第一步:创建Mave…...
STM32F1+HAL库+FreeTOTS学习1——FreeRTOS入门
STM32F1HAL库FreeTOTS学习1——FreeRTOS入门 裸机开发与操作系统嵌入式操作系统简介FreeRTOS简介FreeRTOS的几个重要概念任务调度器任务状态状态列表 裸机开发与操作系统 在以往的嵌入式学习中,我们最常用的就是裸机开发,所谓裸机开发就是指在没有操作系…...
杭州代理记账报税全程托管专业实力全面指南
杭州代理记税报税服务可以为企业提供全程托管财务管理解决方案,确保企业的财务工作专业、高效、合规。以下是杭州代理记税报税服务全面指南: https://www.9733.cn/news/detail/185.html 一、代理记账报税服务的内容 基础服务: 每日记…...
PHP 界的扛把子 Swoole 异步通信利器
大家好,我是码农先森。 引言 我今天主要介绍的内容是包括但不仅限于 Swoole ,也有一部分 Go 语言的内容。 为什么要介绍 Swoole ? 先说一说背景吧,我们项目组之前要为《香港 01》开发一个积分系统的项目,这个系统的主要功能包…...
40.连接假死-空闲检测-发送心跳
连接假死情况 1.网络设备出现故障,例如网卡,机房等。底层的TCP连接已经断开,但应用程序没有感知到,仍然占着资源。 2.公网网络不稳定,出现丢包。若果连续出现丢包,这时现象就是客户端数据发不出去,服务端也一直收不到数据,就这么一直耗着。 3.应用程序线程阻塞,无法…...
hdfs高可用文件系统架构
1、整体架构 2、角色简介 2.1、namenode NameNode 是 HDFS 集群中的核心组件,负责管理文件系统的元数据、处理客户端请求、管理数据块、确保数据完整性和高可用性。由于其重要性,NameNode 的性能和可靠性直接影响整个 HDFS 集群的性能和可靠性。在生产…...
从官方源码精简出第1个FreeRTOS程序
一、下载官方源码 1、打开百度搜索freerots,找到官网:FreeRTOS官网 2、将源码解压到没有中文目录的路径下 二、删减目录 1、删除FreeRTOS-Plus和tools 2、删除FreeRTOS/Demo下除CORTEX_STM32F103_Keil外的所有文件 3、删除FreeRTOS\Source\portable下除RVDS和MemM…...
K8S认证|CKS题库+答案| 11. AppArmor
目录 11. AppArmor 免费获取并激活 CKA_v1.31_模拟系统 题目 开始操作: 1)、切换集群 2)、切换节点 3)、切换到 apparmor 的目录 4)、执行 apparmor 策略模块 5)、修改 pod 文件 6)、…...
pam_env.so模块配置解析
在PAM(Pluggable Authentication Modules)配置中, /etc/pam.d/su 文件相关配置含义如下: 配置解析 auth required pam_env.so1. 字段分解 字段值说明模块类型auth认证类模块,负责验证用户身份&am…...
Mac软件卸载指南,简单易懂!
刚和Adobe分手,它却总在Library里给你写"回忆录"?卸载的Final Cut Pro像电子幽灵般阴魂不散?总是会有残留文件,别慌!这份Mac软件卸载指南,将用最硬核的方式教你"数字分手术"࿰…...
涂鸦T5AI手搓语音、emoji、otto机器人从入门到实战
“🤖手搓TuyaAI语音指令 😍秒变表情包大师,让萌系Otto机器人🔥玩出智能新花样!开整!” 🤖 Otto机器人 → 直接点明主体 手搓TuyaAI语音 → 强调 自主编程/自定义 语音控制(TuyaAI…...
UR 协作机器人「三剑客」:精密轻量担当(UR7e)、全能协作主力(UR12e)、重型任务专家(UR15)
UR协作机器人正以其卓越性能在现代制造业自动化中扮演重要角色。UR7e、UR12e和UR15通过创新技术和精准设计满足了不同行业的多样化需求。其中,UR15以其速度、精度及人工智能准备能力成为自动化领域的重要突破。UR7e和UR12e则在负载规格和市场定位上不断优化…...
微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据
微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据 Power Query 具有大量专门帮助您清理和准备数据以供分析的功能。 您将了解如何简化复杂模型、更改数据类型、重命名对象和透视数据。 您还将了解如何分析列,以便知晓哪些列包含有价值的数据,…...
网站指纹识别
网站指纹识别 网站的最基本组成:服务器(操作系统)、中间件(web容器)、脚本语言、数据厍 为什么要了解这些?举个例子:发现了一个文件读取漏洞,我们需要读/etc/passwd,如…...
推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材)
推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材) 这个项目能干嘛? 使用 gemini 2.0 的 api 和 google 其他的 api 来做衍生处理 简化和优化了文生图和图生图的行为(我的最主要) 并且有一些目标检测和切割(我用不到) 视频和 imagefx 因为没 a…...
Golang——9、反射和文件操作
反射和文件操作 1、反射1.1、reflect.TypeOf()获取任意值的类型对象1.2、reflect.ValueOf()1.3、结构体反射 2、文件操作2.1、os.Open()打开文件2.2、方式一:使用Read()读取文件2.3、方式二:bufio读取文件2.4、方式三:os.ReadFile读取2.5、写…...
WPF八大法则:告别模态窗口卡顿
⚙️ 核心问题:阻塞式模态窗口的缺陷 原始代码中ShowDialog()会阻塞UI线程,导致后续逻辑无法执行: var result modalWindow.ShowDialog(); // 线程阻塞 ProcessResult(result); // 必须等待窗口关闭根本问题:…...

