I am refactoring my Android app for an University project to use Architecture Components and I am having a hard time implementing two-way data binding on a SwitchCompat
. The app has got a simple user interface with a TextView
displaying the status of location updates and the aforementioned SwitchCompat
, which toggles on and off location updates.
For now I am using one-way data binding on the SwitchCompat
's checked
attribute, but would like to use two-way databinding.
The current implementation, using a Model-View-ViewModel architecture is the following:
MainViewModel.java:
public class MainViewModel extends ViewModel {
private LiveData<Resource<Location>> mLocationResource;
public MainViewModel() {
mLocationResource = Repository.getInstance().getLocationResource();
}
public LiveData<Resource<Location>> getLocationResource() {
return mLocationResource;
}
public void onCheckedChanged (Context context, boolean isChecked) {
if (isChecked) {
Repository.getInstance().requestLocationUpdates(context);
} else {
Repository.getInstance().removeLocationUpdates(context);
}
}
}
Resource<Location> (saw the idea here) is a class holding nullable data (Location) and a non null state the TextView
can handle:
State.java
public enum State {
LOADING,
UPDATE,
UNKNOWN,
STOPPED
}
And now the android:onCheckedChanged
implementation in fragment_main.xml:
android:onCheckedChanged="@{(buttonView, isChecked) -> viewModel.onCheckedChanged(context, isChecked)}"
And finally the custom binding adapter to convert from state to boolean checked state:
@BindingAdapter({"android:checked"})
public static void setChecked(CompoundButton view, Resource<Location> locationResource) {
State state = locationResource.getState();
boolean checked;
if (state == State.STOPPED) {
checked = false;
} else {
checked = true;
}
if (view.isChecked() != checked) {
view.setChecked(checked);
}
}
and the implementation of the android:checked
attribute in fragment_main.xml:
android:checked="@{viewModel.getLocationResource}"
As the Android Developers guide I linked above said, how can I do all the work inside android:checked
instead of having both android:checked
and android:onCheckedChanged
(one-way databinding to two-way data binding)?
Also, please let me know if you think the architecture/logic of my app can be improved :)
At the end, I gave up trying to convert from one-way data binding to two-way data binding, but I managed to simplify a little bit the android:checked
attribute:
I replaced value
"@{viewModel.getLocationResource}"
with
"@{viewModel.locationResource.state != State.STOPPED}"
and completely removed the android:checked
@BindingAdapter
.