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…...
网络编程(Modbus进阶)
思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…...
Linux 文件类型,目录与路径,文件与目录管理
文件类型 后面的字符表示文件类型标志 普通文件:-(纯文本文件,二进制文件,数据格式文件) 如文本文件、图片、程序文件等。 目录文件:d(directory) 用来存放其他文件或子目录。 设备…...
Zustand 状态管理库:极简而强大的解决方案
Zustand 是一个轻量级、快速和可扩展的状态管理库,特别适合 React 应用。它以简洁的 API 和高效的性能解决了 Redux 等状态管理方案中的繁琐问题。 核心优势对比 基本使用指南 1. 创建 Store // store.js import create from zustandconst useStore create((set)…...
在Ubuntu中设置开机自动运行(sudo)指令的指南
在Ubuntu系统中,有时需要在系统启动时自动执行某些命令,特别是需要 sudo权限的指令。为了实现这一功能,可以使用多种方法,包括编写Systemd服务、配置 rc.local文件或使用 cron任务计划。本文将详细介绍这些方法,并提供…...
GitHub 趋势日报 (2025年06月08日)
📊 由 TrendForge 系统生成 | 🌐 https://trendforge.devlive.org/ 🌐 本日报中的项目描述已自动翻译为中文 📈 今日获星趋势图 今日获星趋势图 884 cognee 566 dify 414 HumanSystemOptimization 414 omni-tools 321 note-gen …...
关于 WASM:1. WASM 基础原理
一、WASM 简介 1.1 WebAssembly 是什么? WebAssembly(WASM) 是一种能在现代浏览器中高效运行的二进制指令格式,它不是传统的编程语言,而是一种 低级字节码格式,可由高级语言(如 C、C、Rust&am…...
【论文阅读28】-CNN-BiLSTM-Attention-(2024)
本文把滑坡位移序列拆开、筛优质因子,再用 CNN-BiLSTM-Attention 来动态预测每个子序列,最后重构出总位移,预测效果超越传统模型。 文章目录 1 引言2 方法2.1 位移时间序列加性模型2.2 变分模态分解 (VMD) 具体步骤2.3.1 样本熵(S…...
精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南
精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南 在数字化营销时代,邮件列表效度、用户参与度和网站性能等指标往往决定着创业公司的增长成败。今天,我们将深入解析邮件打开率、网站可用性、页面参与时…...
华硕a豆14 Air香氛版,美学与科技的馨香融合
在快节奏的现代生活中,我们渴望一个能激发创想、愉悦感官的工作与生活伙伴,它不仅是冰冷的科技工具,更能触动我们内心深处的细腻情感。正是在这样的期许下,华硕a豆14 Air香氛版翩然而至,它以一种前所未有的方式&#x…...
GitFlow 工作模式(详解)
今天再学项目的过程中遇到使用gitflow模式管理代码,因此进行学习并且发布关于gitflow的一些思考 Git与GitFlow模式 我们在写代码的时候通常会进行网上保存,无论是github还是gittee,都是一种基于git去保存代码的形式,这样保存代码…...

