Faster Android development with data binding

Android Data Binding creates a link between UI layer and the underlying data model that holds the information to display. In normal Android app, it is necessary to find the view and update the content. Every time data changes the User Interface widget (TextView, ImageView etc.) bound to it is needs to be update. Lots of hours were wasted on writing and maintaining trivial and almost useless code occupying tens or even hundreds of lines in almost all Activity.

Android Data Binding library minimize the code for app logic with its UI view. It eliminates the need for these method calls “findViewById” and “setText.”
The real power of data binding is when the updating of a value occurs at many points in an application code. In that situation, the developer doesn’t have to keep track of all the ways a value can be updated. Using data binding can lead to faster development times, faster execution times and more readable and maintained code.

Android data binding generates binding classes at compile time for layouts.


Getting Ready

The Data Binding Library is available for android platforms from Android 2.1 (API 7) and newer. Add the dataBinding element to your app build.gradle file to enable Data Binding.

android {
    dataBinding.enabled = true
}


Binding Layout and Objects

Binding layout files must be configured slightly differently from default layout files. All layout files that intend to use data binding techniques must have a layout<> root tag.

To bind objects it is required to add data<> tag within the layout tag, before the UI view root. data<> element can have multiple variable<> tag within it that describes a property that can be used within the layout.

Our sample activity_main.xml layout would be looks like:

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    tools:context="com.androidjavapoint.databindingsample.MainActivity">

    <data>
        <variable
            name="user"
            type="com.androidjavapoint.databindingsample.User" />
    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:paddingBottom="@dimen/activity_vertical_margin"
        android:paddingLeft="@dimen/activity_horizontal_margin"
        android:paddingRight="@dimen/activity_horizontal_margin"
        android:paddingTop="@dimen/activity_vertical_margin">

        <TextView
            android:id="@+id/textFirstName"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{user.firstname}" />

        <TextView
            android:id="@+id/textLastName"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{user.lastname}" />
    </LinearLayout>

</layout>


User.java

public class User {
   /* constructor */
    private String firstname;
    private String lastname;
    
   /* getters and setters */

}

In the layout above, you can see that <layout> used as a root tag and User.java is used as a data object in the <variable> tag inside <data> tag. Apart from this TextViews have their text set using data binding “@{}” syntax (@{user.firstname} and @{user.lastname}).


Data Binding Activity

Now we have a layout file that is data binding capable. To utilize its data binding ability we have to load it in a different way. With data binding, a Binding class is auto generated from your layout file. By default, Binding class is generated based on the layout file name converted into CamelCase with “Binding” suffix added to it like activity_main.xml will result in a class called ActivityMainBinding.

To associate this generated binding class, need to invoke setContentView of DataBindingUtil class like.

MainActivity.java

// This was the typical way
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
   
    setContentView(R.layout.activity_main);
    final TextView textFirstName = (TextView)findViewById(R.id.textFirstName);
    final TextView textLastName = (TextView)findViewById(R.id.textLastName);
    
    textFirstName.setText("TestFirstName");
    textLastName.setText("textLastName");
}


// This was the new way to do using data binding
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
    
    User myUser = new User("TestFirstName", "TestLastName");
    binding.setUser(myUser);
}

Data binding also do automatic null checks, which is really cool. If you want to access the name, but user is null, how much of pain in the neck would it be to write user null ? null : user.firstName null ? :? You don’t want to do that. Now, if contact is null, the whole expression in null.

You can use

Ternary Operator
<TextView
android:text="@{user.lastName != null ? user.lastName : user.name}”/>

Type Conversion
<TextView
android:text="@{String.valueOf(user.age)}"/>

Resources and String
<TextView
android:padding="@{isBig ? @dimen/bigPadding : @dimen/smallPadding}"/>

String formatting
<TextView
android:text="@{@string/nameFormat(firstName, lastName)}"/>

Inline plurals
<TextView
android:text="@{@plurals/employee(employeeCount)}"/>

Imports
<data>
            <import type="com.androidjavapoint.User"/>
            <import type="java.util.List"/>
            <variable name="user" type="User"/>
            <variable name="userList" type="List<User>"/>
</data>


Event Handling
Using data binding you can also handle events right from the layout xml using either

            1. Method references, or
      2. Listener bindings


Method References

Events can be bound to handler methods directly, similar to the way android:onClick can be assigned to a method in an Activity. One major advantage compared to the View#onClick attribute is that the expression is processed at compile time, so if the method does not exist or its signature is not correct, you receive a compile time error.

For example, we create a class ActivityHandler, with a simple method called onButtonClick to handle button clicks like-

public class ActivityHandler {
    public void onButtonClick (View view) {
            // do stuff
    }
}

In the layout file, declare ActivityHandler variable, and set the Button android:onClick using “@{buttonHandler:: onButtonClick }”.

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
        <variable
            name="buttonHandler"
            type="com.androidjavapoint.databindingsample.ActivityHandler"/>
    </data>
    <RelativeLayout>
    ...
        <Button
            android:id="@+id/finishActivityButton"
            android:onClick="@{buttonHandler::onButtonClick}"/>
    </RelativeLayout>
</layout>


Listener Bindings

These are lambda expressions that are evaluated when the event happens. Data binding always creates a listener, which it sets on the view. When the event is dispatched, the listener evaluates the lambda expression.

public class Presenter {
    public void onSaveClick(Task task){}
}

Then you can bind the click event to your class as follows:

  <?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
      <data>
          <variable name="task" type=" com.androidjavapoint.databindingsample Task" />
          <variable name="presenter" type=" com.androidjavapoint.databindingsample.Presenter" />
      </data>
      <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent">
          <Button android:layout_width="wrap_content" android:layout_height="wrap_content"
          android:onClick="@{() -> presenter.onSaveClick(task)}" />
      </LinearLayout>
  </layout>


Observable Objects

Another way to achieve data change notifications involves the use of Observable objects. These are objects that either implement the Observable interface, or extend the BaseObservable class.

In case of implementing Observer interface in each setter method, called notifyPropertyChanged() method, and for each getter, add @Bindable annotation.

BaseObservable class:

Suppose you have User class and used it in the layout xml to populate data on UI.  So while extending it via BaseObservable class along with required changes as mention then whenever the value of User gets change it will notify directly to UI.

BaseObservable

private static class User extends BaseObservable {

   private String firstName;
   private String lastName;
   
   @Bindable
   public String getFirstName() {
       return this.firstName;
   }
   
   @Bindable
   public String getLastName() {
       return this.lastName;
   }
   
   public void setFirstName(String firstName) {
       this.firstName = firstName;
       notifyPropertyChanged(BR.firstName);
   }
   
   public void setLastName(String lastName) {
       this.lastName = lastName;
       notifyPropertyChanged(BR.lastName);
   }
   
}

The Bindable annotation generates an entry in the BR class file during compilation. The BR class is generated file like R class. Here notify is done by adding notifyPropertyChanged.


Observable interface:

Android data binding gives you the PropertyChangeRegistry class that lets you essentially take those callbacks and notify them. 

Observer

public class User implements Observable {
    private PropertyChangeRegistry registry = new PropertyChangeRegistry();

   private String firstName;
   private String lastName;

   @Bindable
   public String getFirstName() {
       return this.firstName;
   }

   @Bindable
   public String getLastName() {
       return this.lastName;
   }

   public void setFirstName(String firstName) {
       this.firstName = firstName;
       registry.notifyChange(this, BR.firstName);

   }

   public void setLastName(String lastName) {
       this.lastName = lastName;
       registry.notifyChange(this, BR.lastName);
   }


    @Override
    public void addOnPropertyChangedCallback(OnPropertyChangedCallback callback) {
        registry.add(callback);
    }

    @Override
    public void removeOnPropertyChangedCallback(OnPropertyChangedCallback callback) {
        registry.remove(callback);
    }
}


ObservableField

The observer using @Bindable and notifyPropertyChanged getters and setters in model class User is bulky Right? They clutter up the code and force us to do a lot of routine work.

ObservableField are autonomous observable objects with one field. You can access them with get() and set() methods that automatically notify View about changes. To use it you need to create a public final field in your class.

public class User {
    public final ObservableField<String> firstname = new ObservableField<>();
    public final ObservableField<String> lastname = new ObservableField<>();
}

In Java class access getter and setter looks like-
user.firstName.set("TestName");
String = user.lastName.get();

You can use these as normal properties in binding expressions:
<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@{user.firstName}"/>


ObservableMap

With the ObservableMap, you can access values in your map like any normal map and the UI will be updated when changes occur.
<data>
    <variable name="user"
    type="android.databinding.ObservableMap&lt;String, Object&gt;"/>
</data>
<!-- ... -->
<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text=' @{user["firstName"]} '/>

And you’d use the ObservableMap in your code:

ObservableMap<String, Object> user = new ObservableArrayMap<>();
binding.setUser(user);
user.put("firstName", "Test Name");

Any time the product object changes, it will update the UI.


BindingAdapter

Sometimes we want to do something more complex than simply calling a setter on the View. You can use it to redefine the behavior of the existing attributes and create your own attributes without thinking about attrs.xml. A very common example is loading images off the UI thread.

In order to do it you need to create a public static method accepting as input View of the necessary type and value we specify in the layout. The method itself should have @BindingAdapter annotation and in its body you should specify string with the name of the attribute.

<ImageView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:imageUrl="@{user.imageUrl}"/>

If we did not do anything then data binding system would look for a setImageUrl() method on ImageView and not find it. Here we have created a way to set the “app:imageUrl” attribute.  You can also use default “android:src” attribute instead of create own.

@BindingAdapter("imageUrl")
public static void setImageUrl(ImageView imageView, String url) {
    if (url == null) {
        imageView.setImageDrawable(null);
    } else {
        // load image from URL
    }
}

As you can see now we can do whatever we want in that code. We can now load off the UI thread, just like we want to.

Conclusion

As we have noticed Android data binding is a very interesting and powerful feature and it can simplify a lot app building. It avoids the use of reflection and generates binding classes at compile time for layouts you indicate will use data binding. Also, the view hierarchy is only traversed once to find your views. For a more in depth and longer discussion, check out the data binding android developer article.

To find more interesting topics on Software development follow me at https://medium.com/@ankit.sinhal

You can also find my Android Applications on play store


Comments

  1. The blog gave me idea about the android data binding My sincere thanks for sharing this post and please continue to share this post
    Android Training in Chennai

    ReplyDelete
  2. really you have posted an informative blog. it will be really helpful to many peoples. so keep on sharing such kind of an interesting blogs.
    android training in chennai

    ReplyDelete
  3. This book is highly recommended for Android developers as the book contains the best part in Android application development. I would like to suggest refer Android studio by Google which is also a good guide on development.
    Android Training in Chennai | Cloud Computing Training in Chennai

    ReplyDelete
  4. We share this kind of information very useful.Google update for many thinks apps applications.I suggest android studio google guide of development.Are looking for Big Data Developer Course reach us,Want to be looking learn now Big Data Developer reach Hadoop Training in Chennai

    ReplyDelete
  5. You provide a very good information.Really you are a skilled blogger.Thanks for sharing. keep sharing more blogs.

    Android Training in Chennai

    ReplyDelete
  6. Thank you for sharing such an informative post.
    Android Training in velachery also provide excellent android training with real time experience.

    ReplyDelete
  7. This comment has been removed by the author.

    ReplyDelete
  8. This comment has been removed by the author.

    ReplyDelete
  9. I would say while reading your article i felt very proud, because the information you written very useful, please keep posting this type of articles. If you guys looking for a training institutes for Android Training in Chennai. Please click below link. Best Android Training Institute in Chennai | Best Android Training Course in Chennai or call me at +91 86818 84318

    ReplyDelete
  10. Thank you for your post. This is excellent information. It is amazing and wonderful to visit your site. keep posting
    Best Software Training Centre in Chennai | Software Training Centre in Chennai

    ReplyDelete
  11. Great post and informative blog.it was awesome to read, thanks for sharing this great content to my vision.
    embedded rtos training in chennai | embedded testing training in chennai .

    ReplyDelete
  12. I believe there are many more pleasurable opportunities ahead for individuals that looked at your site. RPA Training in Chennai | Blue Prism Training in Chennai

    ReplyDelete
  13. Really awesome blog. Your blog is really useful for me
    Regards,
    Data Science Course in Chennai

    ReplyDelete
  14. its a good post and keep posting good article.its very interesting to read.
    Regards,
    Data Science Course in Chennai | R Programming Training in Chennai | Python Training in Chennai

    ReplyDelete
  15. Thanks for the wonderful tip! Very detailed and informative. Easy enough for a beginner like me to understand.
    Data Science Training in Chennai | Data Science Course in Chennai

    ReplyDelete
  16. Me2call4u is just what it sounds like - a place to meet new friends. With Me2call4u, you can find new friendships from your own city or from around the world. Random video chat

    ReplyDelete

Post a Comment

Popular posts from this blog

Android Performance: Avoid using ENUM on Android

Android O: Impact On Running Apps And Developer Viewpoint

Smart way to update RecyclerView using DiffUtil