android-mvvm
android-mvvm copied to clipboard
NonFunctional ViewModels OR ViewModels with lifecycle OR Better Two Way Binding Field
Usecase: Two Way binding is required Value of the field needs to be updated from an observable.
As of now, two way binding has been implemented using vanilla ObservableField. Hence, it has no functionality to bind to an Observable. Hence, the only way is to subscribe to the observable externally. However, that requires knowledge about lifecycle.
Idea is to provide a bindingadapter: bind:lifecycle_to: @{vm}, between View and any instance of Connectable interface.
The adapter will add an AttachStateListener and invoke connect when the view is subscribed and unsubscribe when view is detached.
ViewModels can then implement connect method and do the subscriptions there.
Not Functional any more 😭
Of course, it would be ideal to find a way around this. Allowing subscriptions in ViewModels would make the pattern weak, as it won't enforce functionalness constraint.
As twowaybinding behaviour is analogous to BehaviourSubject, it can be used to allow creating ObservableFields from observables while still allowing two way binding. Need to think about all edge cases here. If this works, this would be the way to go.
Looking for other usecases
Although subject could solve the top usecase, there could be other usecases, where subscribing cannot be moved to binding layer.
@manas-chaudhari Any update on implementing ViewModel lifecycle ?
No update on this.
You can implement this through a BindingAdapter. It should roughly look like this:
public static void bindLifecycle(View view, Connectable connectable) {
if (connectable != null) {
newListener = new OnAttachStateChangeListener() {
private Subscription subscription;
@Override
public void onViewAttachedToWindow(View v) {
subscription = connectable.connect();
}
@Override
public void onViewDetachedFromWindow(View v) {
subscription.unsubscribe();
}
};
}
// TODO: remove old listener using ListenerUtil
if (newListener != null) {
view.addOnAttachStateChangeListener(newListener);
}
}
Then you can make your ViewModel implement Connectable interface.
I haven't tried this myself. But I think this should work.
Really nice, with this we are now able to automatically unsubscribe from Subscriptions. But what if I'd like to unsubscribe in onPause() and then subscribe again in onResume() ? For example I would like to stop scanning for BLE devices in onPause(), and then restart it.
I'm starting to get the feeling that we will end up wiring the MvvmActivity's lifecycle to the ViewModel.
Adding https://github.com/manas-chaudhari/android-mvvm/pull/42 for reference.
An approach to access view lifecycle in ViewModels was discussed in https://github.com/manas-chaudhari/android-mvvm/pull/42#issuecomment-268178199. Idea is to pass lifecycle to ViewModel as a dependency. NaviComponent can be used to represent lifecycle.
It would be interesting to create a documentation/example for this approach. @szantogab Would you like to take this up?