
MVVM架构(Android,是的学校不教...抽象)
MVVM(Model-View-ViewModel)是一种软件架构模式,广泛应用于 Android 应用开发中,用于分离关注点并提高代码的可维护性和可测试性。以下是 MVVM 在 Android 中的具体含义和组成部分:
1. Model(模型层)
职责:负责数据的获取、存储和管理。
实现方式:
数据可以来自本地数据库(如 Room)、网络请求(如 Retrofit)或其他数据源。
提供数据给 ViewModel 层。
示例:
MVVM(Model-View-ViewModel)是一种软件架构模式,广泛应用于 Android 应用开发中,用于分离关注点并提高代码的可维护性和可测试性。以下是 MVVM 在 Android 中的具体含义和组成部分:
1. Model(模型层)
职责:负责数据的获取、存储和管理。
实现方式:
数据可以来自本地数据库(如 Room)、网络请求(如 Retrofit)或其他数据源。
提供数据给 ViewModel 层。
示例:
2. View(视图层)
职责:负责 UI 的展示和用户交互。
实现方式:
使用 XML 文件定义布局。
通过绑定机制(Data Binding 或 View Binding)与 ViewModel 进行交互。
特点:
不直接与 Model 层交互。
只负责显示数据和响应用户操作。
3. ViewModel(视图模型层)
职责:
充当 Model 和 View 之间的桥梁。
负责准备和管理 View 所需的数据。
处理用户的输入并更新 Model。
特点:
生命周期感知(Lifecycle-Aware),不会因为配置更改(如屏幕旋转)而丢失数据。
使用 LiveData 或 StateFlow 等观察型数据结构,通知 View 数据变化。
示例:
public class UserViewModel extends ViewModel {
private MutableLiveData<UserModel> userLiveData = new MutableLiveData<>();
public LiveData<UserModel> getUser() {
return userLiveData;
}
public void loadUser() {
// 模拟从 Model 层加载数据
UserModel user = new UserModel();
user.setName("Alice");
user.setEmail("alice@example.com");
userLiveData.setValue(user);
}
}
4. Android 中的实现工具
Data Binding / View Binding:
用于将 View 和 ViewModel 绑定在一起,减少手动操作控件的代码。
LiveData / StateFlow:
观察型数据容器,当数据发生变化时自动通知 View 更新。
Lifecycle:
提供生命周期感知功能,确保 ViewModel 在 Activity/Fragment 生命周期内有效。
5. MVVM 的优点
分离关注点:UI 层和业务逻辑层分离,便于维护和扩展。
可测试性:ViewModel 不依赖于 View,可以单独进行单元测试。
生命周期管理:ViewModel 自动处理 Activity/Fragment 的生命周期问题,避免内存泄漏。
6. 简单示例
以下是一个完整的 MVVM 示例:
(1) Model 层
public class UserModel {
private String name;
private String email;
public UserModel(String name, String email) {
this.name = name;
this.email = email;
}
public String getName() { return name; }
public String getEmail() { return email; }
}
(2) ViewModel 层
public class UserViewModel extends ViewModel {
private MutableLiveData<UserModel> userLiveData = new MutableLiveData<>();
public LiveData<UserModel> getUser() {
return userLiveData;
}
public void loadUser() {
UserModel user = new UserModel("Alice", "alice@example.com");
userLiveData.setValue(user);
}
}
(3) View 层(XML + Data Binding)
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="viewModel"
type="com.example.UserViewModel" />
</data>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:text="@{viewModel.user.name}"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:text="@{viewModel.user.email}"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
</layout>
当然,以下是每一行代码的详细解释:
xml
深色版本
<layout xmlns:android="http://schemas.android.com/apk/res/android">
定义一个根元素
<layout>
,这是 Data Binding 布局文件的根标签。xmlns:android="http://schemas.android.com/apk/res/android"
:声明 Android 命名空间,以便在布局文件中使用 Android 属性。
xml
深色版本
<data>
开始定义数据绑定相关的变量和导入的类。
这个块内的内容用于声明可以在布局文件中使用的变量和表达式。
xml
深色版本
<variable
name="viewModel"
type="com.example.UserViewModel" />
声明一个名为
viewModel
的变量,其类型为com.example.UserViewModel
。这个变量可以在布局文件中使用,用于访问
UserViewModel
中的数据。
xml
深色版本
</data>
结束
<data>
标签,表示数据绑定变量声明结束。
xml
深色版本
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
定义一个
LinearLayout
布局容器。android:orientation="vertical"
:设置布局的方向为垂直排列。android:layout_width="match_parent"
:设置布局的宽度为父视图的宽度。android:layout_height="match_parent"
:设置布局的高度为父视图的高度。
xml
深色版本
<TextView
android:text="@{viewModel.user.name}"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
定义一个
TextView
控件。android:text="@{viewModel.user.name}"
:使用 Data Binding 表达式将TextView
的文本内容绑定到viewModel
对象的user
属性的name
字段。android:layout_width="wrap_content"
:设置TextView
的宽度根据内容自动调整。android:layout_height="wrap_content"
:设置TextView
的高度根据内容自动调整。
xml
深色版本
<TextView
android:text="@{viewModel.user.email}"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
定义另一个
TextView
控件。android:text="@{viewModel.user.email}"
:使用 Data Binding 表达式将TextView
的文本内容绑定到viewModel
对象的user
属性的email
字段。android:layout_width="wrap_content"
:设置TextView
的宽度根据内容自动调整。android:layout_height="wrap_content"
:设置TextView
的高度根据内容自动调整。
xml
深色版本
</LinearLayout>
结束
LinearLayout
标签,表示线性布局容器结束。
xml
深色版本
</layout>
结束
<layout>
标签,表示整个 Data Binding 布局文件结束。
总结
这个 XML 文件是一个 Data Binding 布局文件,用于在 Android 应用程序中绑定数据。它包含一个 LinearLayout
布局容器,其中有两个 TextView
控件,分别显示从 UserViewModel
获取的用户姓名和电子邮件地址。通过 Data Binding 表达式,这些 TextView
可以动态地更新显示的内容。
(4) Activity 或 Fragment
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
UserViewModel viewModel = new ViewModelProvider(this).get(UserViewModel.class);
viewModel.loadUser();
setContentView(R.layout.activity_main);
ActivityMainBinding binding = ActivityMainBinding.inflate(getLayoutInflater());
binding.setViewModel(viewModel);
binding.executePendingBindings();
}
}
MutableLiveData<UserModel>与LiveData<UserModel>有区别吗?
是的,MutableLiveData<UserModel>
和 LiveData<UserModel>
之间有一些关键的区别。下面是详细的解释:
LiveData<UserModel>
不可变性:
LiveData
是一个只读的数据持有者类。这意味着其他组件(如 Activity 或 Fragment)可以通过LiveData
观察数据的变化,但不能直接修改这些数据。用途: 主要用于向观察者提供数据更新的通知,而不允许外部直接更改数据。
方法:
getValue()
: 获取当前存储的值。observe(LifecycleOwner owner, Observer<T> observer)
: 添加一个观察者,当数据变化时会通知该观察者。removeObserver(Observer<T> observer)
: 移除指定的观察者。
MutableLiveData<UserModel>
可变性:
MutableLiveData
继承自LiveData
,但它提供了额外的方法来修改存储的数据。用途: 主要用于在
ViewModel
中修改和更新数据,并通过LiveData
将这些变化通知给观察者。方法:
所有
LiveData
的方法。setValue(T value)
: 设置一个新的值,并通知所有活跃的观察者。postValue(T value)
: 在主线程上设置一个新的值,并通知所有活跃的观察者。这个方法适用于从后台线程发布更新。
示例代码对比
LiveData<UserModel>
java
深色版本
public class UserViewModel extends ViewModel {
private final LiveData<UserModel> userLiveData;
public UserViewModel(UserModel userModel) {
this.userLiveData = new MutableLiveData<>(userModel);
}
public LiveData<UserModel> getUser() {
return userLiveData;
}
}
在这个示例中,UserViewModel
接受一个 UserModel
对象并通过构造函数初始化 LiveData
。由于 LiveData
是不可变的,外部无法直接修改 userLiveData
的值。
MutableLiveData<UserModel>
java
深色版本
public class UserViewModel extends ViewModel {
private final MutableLiveData<UserModel> userLiveData = new MutableLiveData<>();
public LiveData<UserModel> getUser() {
return userLiveData;
}
public void loadUser() {
UserModel user = new UserModel("Alice", "alice@example.com");
userLiveData.setValue(user);
}
}
在这个示例中,UserViewModel
内部使用 MutableLiveData
来存储用户数据。通过 loadUser()
方法,可以在需要的时候调用 setValue()
方法来更新 userLiveData
的值,并通知所有观察者。
总结来说,MutableLiveData
提供了修改数据的能力,而 LiveData
则主要用于观察数据的变化。通常情况下,在 ViewModel
中使用 MutableLiveData
来管理数据,并通过返回 LiveData
来让其他组件观察这些数据。