106.map 和 switchMap

相同点与不同点:

相同点:

  • 都是 LiveData 的转换函数: 它们都用于转换一个 LiveData 对象,并返回一个新的 LiveData 对象。
  • 都使用 lambda 表达式进行转换: 它们都接收一个 lambda 表达式作为参数,用于定义转换的逻辑。
  • 生命周期感知: 转换后的 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,请根据需要将文件放到对应的包中。

这个示例包含两个主要部分:

  1. MyViewModel.kt
    在这个 ViewModel 中,我们定义了一个 MutableLiveData 用于跟踪用户输入的数字,并利用 Transformations.map 将数字乘以 10,同时使用 Transformations.switchMap 根据输入数字动态创建一个新的 LiveData,该 LiveData 返回字符串结果。

  2. 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)
}

【详细说明】

  1. MyViewModel.kt

    • 定义一个 MutableLiveData (_inputNumber) 用于存储用户输入的数字。
    • 使用 Transformations.map 将输入的数字乘以 10,生成 multipliedNumber。
    • 使用 Transformations.switchMap 根据 inputNumber 的值动态生成一个新的 MutableLiveData,这里返回 "Result for {number}" 字符串,生成 stringResult。
    • setInputNumber 方法用于更新 _inputNumber 的值,进而触发 LiveData 的数据更新。
  2. MainActivity.kt

    • 使用 viewModels 获取 MyViewModel 实例,观察 multipliedNumber 和 stringResult 两个 LiveData。
    • 当用户在 EditText 中输入数字,并点击按钮时,调用 viewModel.setInputNumber(number) 更新数据;LiveData 数据变化后 UI 自动更新显示转换结果。
  3. activity_main.xml

    • 定义了 EditText、Button、和两个 TextView,它们分别用于输入、提交、展示 map 转换和 switchMap 得到的结果。

你可能感兴趣的:(android)