I think Android DataBinding is one of the best Android libraries long since AppCompat, so does Vector despite all of its limitations. The question remains, how can I diminish its limitation by marrying them together?
Databinding is one of the greatest leap in Android development ecosystem since AppCompat first Introduce, if done properly it will reduce the amount of logic in your activity, especially UI related. You could easily change the state of your layout by passing different value inside. The most important thing is, say goodbye to findViewById and setText. Wohooo!!!
Well before I start marrying this match made in heaven, first let me tell you the basic stuff on how the databinding works. I split it into two parts, the first part I want to talk about the databinding, the second part about Vector and how can we combine them together.
first, on your project build.gradle set Android Plugin for Gradle 1.5.0-alpha1 or higher. This time we will use 2.1.3
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.1.3'
}
}
and in your app build.gradle add the dataBinding
android {
.... dataBinding {
enabled = true
}
}
that’s all you need to setup databinding support, but how do I use it? Ok, first start small.
first create a layout like this
nothing ordinary, but the difference is you will set a data from java file.
How would you normally do it? You would do findViewById() for the TextView and do setText in your activity. What if you have so many UI interaction and showing different state? You will see bunch of setText, setVisibility, and the list goes on…
This is where DataBinding becomes handy. Instead you can pass a ViewModel to act as a reference/bind to the UI state, hence the name is DataBinding or this will lead to MVVM Daahh..
Normal layout, you will see
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
.....>
<--! Body of your layout -->
</LinearLayout>
Instead, you go to your XML layout, and wrap it inside this bracket <layout>
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<LinearLayout
android:id="@+id/content_main"
android:layout_width="match_parent"
....>
<--! Body of your layout-->
</LinearLayout>
</layout>
And it will automatically generate a binding class in your java file, so you can do this to setContentView your layout
ActivityMainBinding binding;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
ActivityMainBinding is your xml in Java representation, if you go to its declaration, it will go to the xml file. Hence the name is the same with your layout file with Binding suffix. It will simply inflate the layout into your activity.
Now how do I bind the data to the layout, you can pass a model to act as a ViewModel, now let’s create ExampleViewModel.java and pass it to your xml like this
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="viewModel"
type="com.bloonerd.vectordatabinding.ExampleViewModel"/>
</data>
<LinearLayout
android:id="@+id/content_main"
....
inside <data> name acts like a variable to the layout, while the type is the Model you reference to. Set the viewModel like this
private String text;
public ExampleViewModel(String text) {
this.text = text;
}
public String getText() {
return text;
}
and on your layout, set the text reference to the getText()
<TextView
android:layout_width="match_parent"
android:layout_height="30dp"
android:background="@color/colorPrimary"
android:textColor="@android:color/white"
android:gravity="center"
android:text="@{viewModel.text}"/>
Wait, why it’s only viewModel.text instead of viewModel.getText? Actually, android DataBinding follows JavaBean convention, so it will ignore suffix is for boolean, and get for other types.
Ok, now let’s bind the ViewModel with the Layout
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = DataBindingUtil.setContentView(MainActivity.this, R.layout.activity_main);
binding.setViewModel(new ExampleViewModel("Hello world"));
that’s it, it will show the Hello World on the blue box. Note that setViewModel function is depending on you variable name inside your xml.
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="viewModel"
if you name it to something else like ironMan it will have setIronMan instead.
What if you want to update the value for example by click a button, this is when BaseObservable come into play. Now on your ExampleViewModel.java extend it to BaseObservable.
public class ExampleViewModel extends BaseObservable {
... @Bindable
public String getText() {
return text;
} public void setText(String text) {
this.text = text;
notifyChange() // it will notify all the @Bindable methods
// or notifyPropertyChanged(BR.text) but need to rebuild
}
viewModel = new ExampleViewModel("Hello world");
binding.setViewModel(viewModel);
}
public void onButtonClick(View view) {
viewModel.setText("It's clicked");
}
What if if I want to bind a TextView to an EditText as I type, the value changes. Well you have it, it’s Two Way DataBinding. In two way databinding, you can call the View method inside your xml, and have the viewModel as the parameter of its method.
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:addTextChangedListener="@{viewModel.textWatcher}"/><TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@{viewModel.inputText}"/>
@Bindable
public String getInputText() {
return inputText;
}
public TextWatcher textWatcher = new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
inputText = s.toString();
notifyChange();
}
};
That’s it for the first part. Next I will talk how can we use the View method in the layout and BindingAdapter in order to bind vector. We will also talk about VectorCompat and how can we diminish its limitation with Databinding..
You can find the project in this link
STAY TUNE!!!