You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何结合LiveData监听SharedPreferences变化并触发网络请求

嘿,这个需求其实挺贴合MVVM架构最佳实践的——用LiveData监听SharedPreferences变化,既能利用它的生命周期感知能力避免内存泄漏,又能优雅地触发网络请求更新数据。我给你梳理一套完整的实现步骤,附带代码示例:

1. 自定义LiveData监听SharedPreferences变化

首先咱们需要一个自定义的LiveData子类,专门用来监听SharedPreferences指定key的变化,把SP的变化转换成LiveData的数据流:

class SharedPreferenceLiveData<T>(
    private val sharedPreferences: SharedPreferences,
    private val key: String,
    private val defaultValue: T
) : LiveData<T>() {

    // SP变化监听器
    private val preferenceChangeListener = SharedPreferences.OnSharedPreferenceChangeListener { _, changedKey ->
        if (changedKey == key) {
            value = getValueFromPreferences()
        }
    }

    override fun onActive() {
        super.onActive()
        // 当有观察者订阅时,立即发送当前值,并注册监听器
        value = getValueFromPreferences()
        sharedPreferences.registerOnSharedPreferenceChangeListener(preferenceChangeListener)
    }

    override fun onInactive() {
        super.onInactive()
        // 当没有观察者时,注销监听器,避免内存泄漏
        sharedPreferences.unregisterOnSharedPreferenceChangeListener(preferenceChangeListener)
    }

    @Suppress("UNCHECKED_CAST")
    private fun getValueFromPreferences(): T {
        return when (defaultValue) {
            is Boolean -> sharedPreferences.getBoolean(key, defaultValue) as T
            is Float -> sharedPreferences.getFloat(key, defaultValue) as T
            is Int -> sharedPreferences.getInt(key, defaultValue) as T
            is Long -> sharedPreferences.getLong(key, defaultValue) as T
            is String -> sharedPreferences.getString(key, defaultValue) as T
            else -> throw IllegalArgumentException("Unsupported type")
        }
    }
}

这个类会在LiveData活跃(有UI组件观察)时自动注册SP监听器,不活跃时自动注销,完美适配Android生命周期。

2. 用Repository整合SP监听与网络请求

接下来创建一个Repository类,负责把SP的变化和网络请求绑定起来。这里用Transformations.switchMap实现:当SP的LiveData值变化时,自动触发新的网络请求,并返回请求结果的LiveData。

先模拟你的网络请求接口(用Kotlin协程的挂起函数):

// 替换成你的实际网络请求逻辑
suspend fun fetchDataWithParams(param1: String, param2: Int): Result<DataModel> {
    return Result.success(DataModel())
}

然后是Repository的实现:

class DataRepository(private val sharedPreferences: SharedPreferences) {

    // 监听SP中param1的变化
    private val param1LiveData = SharedPreferenceLiveData(sharedPreferences, "param1", "")
    // 监听SP中param2的变化
    private val param2LiveData = SharedPreferenceLiveData(sharedPreferences, "param2", 0)

    // 合并参数变化,触发网络请求
    fun getUpdatedData(): LiveData<Result<DataModel>> {
        return Transformations.switchMap(param1LiveData) { param1 ->
            Transformations.switchMap(param2LiveData) { param2 ->
                liveData(Dispatchers.IO) {
                    emit(fetchDataWithParams(param1, param2))
                }
            }
        }
    }
}

如果你的参数更多,可以用MediatorLiveData来合并多个SP参数的变化,只要任意一个参数更新,就会触发新的网络请求。

3. ViewModel中持有Repository,暴露给UI层

ViewModel作为UI和数据层的中间层,直接持有Repository实例,把数据请求的LiveData暴露给Activity/Fragment:

class MainViewModel(application: Application) : AndroidViewModel(application) {
    private val sharedPreferences = application.getSharedPreferences("MyPrefs", Context.MODE_PRIVATE)
    private val repository = DataRepository(sharedPreferences)

    // 暴露给UI观察的LiveData
    val dataLiveData = repository.getUpdatedData()
}
4. 在Activity中观察LiveData,处理结果

最后在你的设置页面或主页面中,观察ViewModel的LiveData,一旦有新的网络请求结果就更新UI:

class MainActivity : AppCompatActivity() {
    private lateinit var viewModel: MainViewModel
    private val sharedPreferences by lazy {
        getSharedPreferences("MyPrefs", Context.MODE_PRIVATE)
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        viewModel = ViewModelProvider(this)[MainViewModel::class.java]

        // 观察数据变化
        viewModel.dataLiveData.observe(this) { result ->
            when (result) {
                is Result.Success -> {
                    // 更新UI,展示新数据
                    updateUI(result.data)
                }
                is Result.Failure -> {
                    // 处理错误
                    showError(result.exception)
                }
            }
        }
    }

    // 模拟设置页面保存参数的方法(比如点击按钮触发)
    fun saveSettings(param1: String, param2: Int) {
        sharedPreferences.edit()
            .putString("param1", param1)
            .putInt("param2", param2)
            .apply()
    }
}
关键注意点
  • 生命周期安全:自定义的SharedPreferenceLiveData会在UI组件销毁时自动注销SP监听器,不会造成内存泄漏。
  • 自动触发请求:只要SP中指定的参数变化,switchMap就会自动触发新的网络请求,无需手动调用API。
  • 线程切换:网络请求在Dispatchers.IO线程执行,结果自动切换到主线程,符合Android线程规范。

内容的提问来源于stack exchange,提问作者nick.tdr

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 09:07:41