首页 > 解决方案 > Android LiveData 和提供者/管理器模式

问题描述

我正在开发一个在 Provider/Manager 中定义数据源的应用程序。这个类(我们称之为它InfoProvider)几乎只是一个黑盒子——它有一些属性,并且在执行时调用这些属性会导致这些属性的更改(类似于 Repository 的工作方式,但它们不是调用返回值,而是执行一个异步调用将导致提供者的一个或多个属性发生变化)。

这个设置是专门针对低功耗蓝牙的——我们都知道它在 Android 上的管理有多糟糕,我想让它尽可能异步,并使用数据绑定+livedata+viewmodels 来实现完全响应的架构。

使用 Xamarin 这很容易,只需将 定义InfoProvider为 ViewModel 中的字段,并绑定到其字段。但是我不一定要公开所有视图模型中的所有字段(有些可能只需要设备的电池状态,有些可能需要完全访问权限,有些可能只执行功能而不等待响应)。对于函数,很容易代理,但对于LiveData<T>我没有找到太多信息。我将如何前进并“绕过” LiveData 字段?

例子:

class InfoProvider {
    var batteryPercent = MutableLiveData<Int>()

    public fun requestBatteryUpdate() {
        [...]
        batteryPercent.value = newValue
    }
}

// ViewModel for accessing device battery, inheriting from architecture ViewModel
class DeviceBatteryViewModel: ViewModel() {
    var batteryPercentage = MutableLiveData<Int>()
    val infoProvider: InfoProvider by inject()

    init {
        // TODO: Subscribe this.batteryPercentage to infoProvider.batteryPercent

    fun onButtonClick() {
        infoProvider.requestBatteryUpdate()
    }
}

class DeviceBatteryFragment: Fragment() {
    val ViewModel: DeviceBatteryViewModel by inject()
    private lateinit var binding: DeviceBatteryBinding

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? =
            DeviceBatteryBinding.inflate(inflater, container, false).also { binding = it }.root

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        binding.viewModel = this.ViewModel
    }

}


// res/layout/fragment_devicebattery.xml

<layout [namespaces]>
    <data class="bindings.DeviceBatteryBinding>
        <variable android:name="viewModel" type=".DeviceBatteryViewModel />
    </data>

    <WhatEverLayout [...]>
        <TextView [...] android:text="@{viewModel.batteryPercentage.toString()}" />
        <Button [...] android:onClick="@{() -> viewModel.onButtonClick()}" />
    </WhatEverLayout>
</layout>

我想避免的是 Rx-style.observe(() -> {}).subscribe(() -> {})类型的交流。可以这样做(即,如果我将值分配给infoProvider.batteryPercentVM 的batteryPercentage字段,它也会接收更新),还是应该直接绑定到 infoProvider?

标签: androidandroid-viewmodelandroid-livedata

解决方案


"pass around" the LiveData field没有调用就没有办法batteryPercent.observe(...)。此外,您将需要使用 aLifecycler Owner来观察该字段(除非您ObserveForever不推荐使用哪个解决方案)。

我的建议是这样的:

InfoProvider {
    val repositoryBatteryUpdate = BehaviorSubject.create<Int>()

    fun observeRepositoryBatteryUpdate(): Observable<Int> {
        return repositoryBatteryUpdate
    }

    fun requestBatteryUpdate(){
        // Pseudo code for actually update

        // Result goes into repositoryBatteryUpdate.onNext(...)
    }
}

ViewModel{
    val status: MutableLiveData<Int>

    init{
        repository.observeRepositoryItems()
            .subscribe( update -> status.postValue(status))
    }

    fun update(){
        repository.requestBatteryUpdate()
    }
}

Fragment{
    viewModel.status.observe() // <-- Here you observe Updates

    viewModel.update()
}

请注意,您必须在 ViewModel onCleared 中处理订阅。
请注意,所有这些都是伪代码,应该比这更干净。


推荐阅读