相同点与不同点:
相同点:
LiveData
的转换函数: 它们都用于转换一个 LiveData
对象,并返回一个新的 LiveData
对象。LiveData
同样具有生命周期感知能力,只有在观察者处于活动状态时才会传递数据。不同点:
特性 | map |
switchMap |
---|---|---|
转换方式 | map 对原始 LiveData 发出的每个值应用转换函数,并将转换后的值发送到新的 LiveData 。转换函数是同步执行的,并且每次原始 LiveData 发出新值时都会执行。 |
switchMap 对原始 LiveData 发出的每个值应用转换函数,但转换函数必须返回另一个 LiveData 对象。switchMap 会订阅转换函数返回的 LiveData 对象,并将该 LiveData 对象发出的值传递给下游的观察者。重要的是,每次原始 LiveData 发出新值时,switchMap 会取消订阅之前返回的 LiveData 对象,并订阅新的 LiveData 对象。这被称为“切换”数据源。 |
转换函数返回值 | map 的转换函数返回的是转换后的值(可以是任何类型)。 |
switchMap 的转换函数返回的是一个新的 LiveData 对象。 |
应用场景 | map 适用于简单的、一对一的数据转换,例如将 Int 转换为 String ,或者对数据进行格式化等。 |
switchMap 适用于需要根据原始 LiveData 的值动态切换数据源的场景。例如,根据用户选择的城市,切换到该城市的天气数据;或者根据用户的搜索关键词,动态发起搜索请求。由于它会取消订阅之前的 LiveData ,因此也适用于避免并发请求的场景。 |
适用性 | 适合简单的同步转换 | 适合动态切换 LiveData 源,处理异步操作,避免并发。 |
总结:
LiveData
中的数据进行简单的转换,并且转换过程是同步的,那么可以使用 map
。LiveData
中的数据动态地切换数据源,或者需要处理异步操作,并且希望避免并发请求,那么可以使用 switchMap
。下面是一个完整的示例,展示如何在 Android 中使用 LiveData 的 map 和 switchMap 方法。示例中的代码文件都采用包名 com.example.myapplication,请根据需要将文件放到对应的包中。
这个示例包含两个主要部分:
MyViewModel.kt
在这个 ViewModel 中,我们定义了一个 MutableLiveData 用于跟踪用户输入的数字,并利用 Transformations.map 将数字乘以 10,同时使用 Transformations.switchMap 根据输入数字动态创建一个新的 LiveData,该 LiveData 返回字符串结果。
MainActivity.kt 与 activity_main.xml
Activity 负责展示 UI,并观察 MyViewModel 中转换后 LiveData 的变化。用户在 EditText 中输入数字,点击按钮更新 ViewModel,LiveData 的变化会自动更新界面。
下面提供完整示例文件:
MyViewModel.kt:
package com.example.myapplication
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.map
import androidx.lifecycle.switchMap
/**
* MyViewModel 演示了如何使用 LiveData 的扩展函数 map 和 switchMap。
*
* - inputNumber: 存储用户输入的数字
* - multipliedNumber: 使用 map 将 inputNumber 的值乘以 10 的结果
* - stringResult: 使用 switchMap,根据 inputNumber 动态生成字符串结果
*/
class MyViewModel : ViewModel() {
// 用户输入的原始数字
/*
MutableLiveData 是 Android Jetpack 中 LiveData 的一个具体实现类,主要用于在 Android 应用中持有可变的数据
并允许观察者(通常是 UI 组件,如 Activity 或 Fragment)监听数据的变化。
ViewModel 是 Android Jetpack 库中的一个类,用于以生命周期感知的方式存储和管理 UI 相关的数据
ViewModel 类旨在保存 UI 数据,并在配置更改(例如屏幕旋转)时保持数据不变。
LiveData:表示这是一个 LiveData 对象,并且该 LiveData 持有的数据类型是 Int(整数)
LiveData 是 Android Jetpack 库中的一个类,用于以生命周期感知的方式持有可观察的数据。
get():表示这是一个只读属性,只能获取属性的值,不能设置属性的值。
_inputNumber 作为内部的可变数据源,允许 ViewModel 修改用户输入的数字。
(val 并不意味着 _inputNumber 所指向的 MutableLiveData 对象的内容是不可变的。)
inputNumber 作为外部的只读数据源,允许 UI 观察用户输入的数字,但防止 UI 直接修改它。
LiveData 用于存储单个 Int (整数) 值
*/
private val _inputNumber = MutableLiveData()
val inputNumber: LiveData get() = _inputNumber
// 使用扩展函数 map 将输入的数字乘以 10
/*
这里的 map 是 LiveData 的一个扩展函数
它允许你将 LiveData 中持有的数据进行转换,并返回一个新的 LiveData 对象,该对象持有转换后的数据。
*/
val multipliedNumber: LiveData = _inputNumber.map { number ->
number * 10
}
// 使用扩展函数 switchMap 当输入数字改变时,动态生成一个新的 LiveData
/*
inputNumber.switchMap 用于对 LiveData 对象 _inputNumber 进行转换,并返回一个新的 LiveData 对象
*/
val stringResult: LiveData = _inputNumber.switchMap { number ->
val resultLiveData = MutableLiveData()
resultLiveData.value = "Result for $number"
resultLiveData
}
// 更新输入数字的方法
fun setInputNumber(number: Int) {
_inputNumber.value = number
}
}
Main.kt:
package com.example.myapplication
import android.os.Bundle
import android.widget.Button
import android.widget.EditText
import android.widget.TextView
import androidx.activity.ComponentActivity
import androidx.activity.viewModels
/**
* MainActivity 通过观察 MyViewModel 中的 LiveData 实现:
* - 显示经过 map 转换后的乘以 10 的结果
* - 显示通过 switchMap 得到的字符串结果
*
* 用户输入数字后点击按钮,即可触发 ViewModel 数值更新,UI 将实时响应数据的变化。
*/
class MainActivity : ComponentActivity() {
// 使用 viewModels 获取 MyViewModel 的实例
private val viewModel: MyViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val etInput = findViewById(R.id.etInput)
val btnSubmit = findViewById
main.xml:
gradle:
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.kotlin.android)
}
android {
namespace = "com.example.myapplication"
compileSdk = 35
defaultConfig {
applicationId = "com.example.myapplication"
minSdk = 24
targetSdk = 35
versionCode = 1
versionName = "1.0"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
kotlinOptions {
jvmTarget = "11"
}
}
dependencies {
implementation(libs.androidx.core.ktx)
implementation(libs.androidx.appcompat)
implementation(libs.material)
implementation(libs.androidx.activity)
implementation(libs.androidx.constraintlayout)
// 添加 Lifecycle LiveData 和 ViewModel 的 KTX 依赖
implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.6.1")
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1")
testImplementation(libs.junit)
androidTestImplementation(libs.androidx.junit)
androidTestImplementation(libs.androidx.espresso.core)
}
【详细说明】
MyViewModel.kt
MainActivity.kt
activity_main.xml