Android LiveData和提供者/管理者模式

时间:2018-09-15 20:17:56

标签: android android-viewmodel android-livedata

我正在开发一个在提供程序/管理器中定义了数据源的应用程序。此类(我们称其为InfoProvider)几乎只是一个黑匣子-它具有一些属性,并在执行时调用这些属性,从而导致这些属性发生更改(类似于Repository的工作方式,但不再调用返回值,它们将执行异步调用,从而导致提供程序的一个或多个属性发生更改。

此设置专用于低功耗蓝牙-我们都知道它在Android上的管理有多么糟糕,我想使其尽可能地异步,并使用databinding + 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样式的.observe(() -> {}).subscribe(() -> {})等类型的交换。可以做到这一点(即如果我将infoProvider.batteryPercent的值分配给VM的batteryPercentage字段,它也将接收更新),还是应该直接绑定到infoProvider?

1 个答案:

答案 0 :(得分:0)

不调用"pass around" the LiveData field便无法进入batteryPercent.observe(...)。此外,您将需要使用Lifecycler 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中处置订阅。
请注意,所有这些都是伪代码,应该比这更清洁。