Tags: android , data-binding , mvvm
This post is not a comprehensive introduction to data binding in Android, it’s a required minimum to get two-way data binding to work, that assumes your project to be configured for data binding already (if it’s not, start here).
Complete source code available here or here.
role | file |
---|---|
Activity: | MainActivity.java |
Model: | not relevant here |
View: | activity_main.xml |
ViewModel: | MainState.java |
This one just glues stuff together:
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityMainBinding amb = DataBindingUtil.setContentView(this,
R.layout.activity_main);
final MainState ms = new MainState();
amb.setState(ms);
// Enable interface only after 2s for some reason
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
ms.fieldsEnabled.set(true);
}
}, 2000);
}
}
Simple UI, with two EditText
s and one CheckBox
:
<?xml version="1.0" encoding="utf-8"?>
<layout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="state"
type="com.meedamian.twoWayBinding.MainState" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp"
tools:context=".MainActivity">
<!-- Basic example -->
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Basic Field"
android:text="@{state.basic}"
android:enabled="@{state.fieldsEnabled}"
android:addTextChangedListener="@{state.onBasicChanged}" />
<!-- Basic + do sth on blur -->
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Blurable Field"
android:text="@{state.blurable}"
android:enabled="@{state.fieldsEnabled}"
android:addTextChangedListener="@{state.onBlurableChanged}"
android:onFocusChange="@{state.onBlurableFocusChange}" />
<!-- Toggles UI availability -->
<CheckBox
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Toggle interface"
android:checked="@{state.fieldsEnabled}"
android:onClick="@{state.onCheckedChanged}" />
</LinearLayout>
</layout>
I hope the code speaks better than any comment I could put here, but if you have any doubts, ask in comments below.
public class MainState extends BaseObservable {
public final ObservableBoolean fieldsEnabled = new ObservableBoolean();
// Basic EditText boilerplate
private String basic;
@Bindable
public String getBasic() {
return basic;
}
private void setBasicAtomic(String basic) {
this.basic = basic;
}
public void setBasic(String basic) {
setBasicAtomic(basic);
notifyPropertyChanged(BR.basic);
}
public TextWatcher onBasicChanged = new SimpleTextWatcher() {
@Override
public void onTextChanged(String newBasic) {
setBasicAtomic(newBasic);
}
};
// Blurable EditText Boilerplate
private String blurable;
@Bindable
public String getBlurable() {
return blurable;
}
private void setBlurableAtomic(String blurable) {
this.blurable = blurable;
}
public void setBlurable(String blurable) {
setBlurableAtomic(blurable);
notifyPropertyChanged(BR.blurable);
}
public TextWatcher onBlurableChanged = new SimpleTextWatcher() {
@Override
public void onTextChanged(String newBlurable) {
setBlurableAtomic(newBlurable);
}
};
public void onBlurableFocusChange(View v, boolean hasFocus) {
if (!hasFocus)
Toast.makeText(v.getContext(), "Field blurred", Toast.LENGTH_SHORT).show();
}
// CheckBox change listener
public void onCheckedChanged(View v) {
fieldsEnabled.set(((CheckBox) v).isChecked());
}
}
Complete source code available here or here.