I'm working on an app where a data source is defined in a Provider/Manager. This class (let's call it InfoProvider
) is pretty much just a black box - it has some properties, and calls that when executed, result in change of these properties (similar to how a Repository work, but instead of calls returning values, they execute an async call that will result in the change of one or more properties of the provider).
This setup is specifically for Bluetooth Low Energy - we all know how badly managed it is on Android, and I wanted to make it as asynchronous as possible, and use databinding+livedata+viewmodels to achieve a fully responsive architecture.
With Xamarin this would be easy, just define the InfoProvider
as a field in the ViewModel, and bind to its fields. However I don't necessarily want to expose all fields in all viewmodels (some might only need the battery status of the device, some might need full access, some might just execute functions without waiting for a response). For functions, it's easy to proxy, but for LiveData<T>
I haven't found much information. How would I go forward and "pass around" the LiveData field?
Example:
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>
What I'd like to avoid is the Rx-style .observe(() -> {})
, .subscribe(() -> {})
etc. kind of exchanges. Can this be done (i.e. if I assign the value of infoProvider.batteryPercent
to the VM's batteryPercentage
field, will it also receive updates), or should I bind directly to the infoProvider?