Vikas Goyal

Android Data Binding – Part 1

What is Data Binding?

DataBinding is to bind an object model to UI element. As in classic approach we usually set the data on view by finding their reference in activity or fragment and then set data on UI element from the business model.

Databinding introduces a clean approach which allows user to bind a viewmodel to the UI element.

It is basically an implementation of MVVM(Model View ViewModel) design pattern.

Problems without data binding

1. Too large Activity/Fragment

Activity and Fragments already have a lot of code in them. If we write view related code in Activity/Fragment like updating text of TextView, setting image on ImageView, then they become unreadable and difficult to manage. One way to slim them down is to encapsulate more logic into custom view classes and directly use these custom widget classes in layouts and use setters to set data on SubViews.

2. Managing Inflated layout files

Usually Android screens are for view-only purposes. When we inflate layout file in Screen we have to find all the view’s reference using auto-generate “R” file to set data. It is bad especially if we need to heavily interact with a View.

Frequently calling findViewById and type casting them in desired view will impact performance, and even if you find them once and hold their reference in global fields it will still add lots of code and variables in an activity or fragment.

Get Started with Data Binding

To get started with data binding one needs to follow the following steps.

  • First make entry for dependency in gradle file using code in project.gradle add following lines

dependencies {
        classpath 'com.android.tools.build:gradle:1.5.0'
        classpath 'com.android.databinding:dataBinder:1.0-rc4'
    }

  • In App main module build.gradle add lines

apply plugin: 'com.android.application'
apply plugin: 'com.android.databinding'
android {
    compileSdkVersion 23
    buildToolsVersion "23.0.2"

    defaultConfig {
     .
    }
}

As you can see now we have to apply plugin ‘com.android.databinding’ to use data binding functionality in app.

Simple Example to use DataBinding:

DataModel

public class Sample {
    private String imageUrl;
    private String title;
  // Getter and setter
}

 
activity_detail.xml

<layout xmlns:android="http://schemas.android.com/apk/res/android">
   <data>
      <variable name="sample" type="com.example.androiddatabinding.model.Sample“/>
   </data>
  <TextView  android:layout_width="match_parent" android:layout_height="wrap_content“  android:id=“@+id/title“  android:text="@{sample.title}" /> </layout>

 
To Start development with the creation of a new layout-file.xml. For Android Databinding support now the root-tag of a layout file is layout as it is shown in activity_details.xml. It is followed by a data and a View-Root-Element, As in activity_details.xml data is Of Sample type and View Element is currently only a TextView.

In the data section we can define variables import classes and write code related to ViewModel which may use within the layout

Now an Activity for the above layout is defined below.

import android.support.v7.app.AppCompatActivity;

public class SampleBindingActivity extends AppCompatActivity{

private ActivityDetailBinding binding;
@Override
	protected void onCreate(Bundle savedInstanceState) {
  		super.onCreate(savedInstanceState);
		  binding = DataBindingUtil.setContentView(this, R.layout.activity_detail);
 		 binding.setSample(sample);
       }
}

 
In the activity, we can now use the method DataBindingUtil.setContentView to set the root-layout of this activity.

DataBindingUtil will generate Binding class for each layout file like it has generated ActivityDetailsBinding for the layout file “activity_details” by making layout file name in Pascal-Case and adding Binding as suffix in it. You can find these auto-generated class under your application package.databinding.

As DataBinding class will create after compilation of code so their can be issue you will not find these classes immediately in Android Studio. But the compilation of the Project runs successful and the app works.

In last we have to set the View model to the binding class, to transfer the View data to the View. This binding class has also holds the reference to all UI-Widget with an ID name without under-score in PascalCase. If you want to access any property of an UI-element, use binding.idOfView to access the view instead of findViewById.

Now take a  example with populating a RecyclerView using databinding

The RecyclerView xml layout file

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 
     xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:orientation="vertical">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/rcv_list_activity_contents"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        />

</LinearLayout>

 
The Activity class which finds the RecyclerView and populates with dummy data so we can use it.

public class ListItemActivity extends AppCompatActivity {
    private BindingTestAdapter mAdapter;
    private List<ListItem> mData = new ArrayList<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.list_activity);
        RecyclerView recyclerView = (RecyclerView) findViewById(R.id.rcv_list_activity_contents);
        recyclerView.setLayoutManager(new LinearLayoutManager(this));
        populateDemoData();
        mAdapter = new BindingTestAdapter(mData);
        recyclerView.setAdapter(mAdapter);
    }
}

 
Xml Layout file for RecyclerView items which takes ListItem as view model.

As you can see on ImageView we are setting image from viewmodel using imageUrl.

To achieve it we have created Binding adapter which reads the attribute key imageUrl and we can write our own implementation of code there. The example of Binding adapter is also attached.

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

    <data>
        <variable
            name="listItem"
            type="databinding.android.com.model.ListItem"/>
    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
                      xmlns:app="http://schemas.android.com/apk/res-auto"
                      xmlns:tools="http://schemas.android.com/tools"
                      android:layout_width="match_parent"
                      android:layout_height="match_parent"
                      android:orientation="horizontal"
                      android:padding="@dimen/space_default">

            <ImageView
                android:id="@+id/imv_list_item_image"
                android:layout_width="50dp"
                android:layout_height="50dp"
                android:src="@drawable/download"
                app:imageUrl="@{listItem.getImageUrl()}"
                />

            <LinearLayout
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_marginLeft="@dimen/space_default"
                android:layout_weight="1"
                android:orientation="vertical">

                <TextView
                    android:id="@+id/txv_list_item_title"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:gravity="center_vertical"
                    android:text="@{listItem.getTitle()}"
                    android:textColor="@android:color/black"
                    android:textSize="16sp"
                    tools:text="Test"/>

                <TextView
                    android:id="@+id/txv_list_item_description"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_marginTop="@dimen/space_default"
                    android:gravity="center_vertical"
                    android:text="@{@string/formatted_string(listItem.getTitle())}"
                    android:textColor="@android:color/black"
                    android:textSize="16sp"
                    tools:text="Test"/>
            </LinearLayout>

        </LinearLayout>

        <View
            android:layout_width="match_parent"
            android:layout_height="1dp"
            android:background="@android:color/black"/>
    </LinearLayout>

</layout>

 
The adapter implementation of RecyclerView items is attached.

Now you just need to use ListItem variable in onBindViewHolder and our xml layout will update the UI element with provided model object.

package databinding.android.com.adapter;

import android.databinding.DataBindingUtil;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.ViewGroup;

import java.util.List;

import databinding.android.com.R;
import databinding.android.com.databinding.BindingListItemBinding;
import databinding.android.com.model.ListItem;

public class BindingTestAdapter extends RecyclerView.Adapter<BindingTestAdapter.BindingTestViewHolder> {
    private final List<ListItem> mData;

    public BindingTestAdapter(List<ListItem> pData) {
        mData = pData;
    }


    @Override
    public BindingTestAdapter.BindingTestViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        BindingListItemBinding binding = DataBindingUtil.inflate(LayoutInflater.from(parent.getContext())
                , R.layout.binding_list_item, parent, false);
        return new BindingTestViewHolder(binding);
    }

    @Override
    public void onBindViewHolder(BindingTestAdapter.BindingTestViewHolder holder, int position) {
        holder.mBinding.setListItem(mData.get(position));
    }

    @Override
    public int getItemCount() {
        return mData.size();
    }

    @Override
    public int getItemViewType(int position) {
        return 0;
    }

    static class BindingTestViewHolder extends RecyclerView.ViewHolder {
        private final BindingListItemBinding mBinding;

        public BindingTestViewHolder(BindingListItemBinding pBinding) {
            super(pBinding.getRoot());
            mBinding = pBinding;
        }
    }
}

 

Formatted String

Make entry in strings.xml file for

<string name="formatted_string" formatted="true">%s : Description</string>

 

Uses
android:text="@{@string/formatted_string(listItem.getTitle())}"

As you can see “formatted_string” accept one argument and in setting text we have pass argument value in parameter of “formatted_string”

Binding Adapter

Binding adapters are useful for other types of customizations. For example, a custom loader can be called off-thread to load an image.

Developer-created binding adapters will override the data binding default adapters when there is a conflict.

@BindingAdapter({"bind:imageUrl"})
public static void loadImage(ImageView view, String url) {
   Picasso.with(view.getContext().getApplicationContext())
           .load(url)
           .fit()
           .centerInside()
           .into(view);
}

This is the first part of Data Binding Other more functionality and features of data-binding will be cover in next up-coming post.

So far in Part 1 of Android Data Binding we have covered :-

  1. Simple UI with Data-binding.
  2. How to avoid use of findViewById.
  3. Implementation of RecyclerView Using Data-binding.
  4. Parsing formatted string directly from xml with field values.
  5. Using Binding- Adapter for custom method or providing utility using data from View-model.

In Part 2, I will be covering the following topics:

  1. Binding Events.
  2. Expression Language
  3. Data Objects
  4. Observable Objects

Stay tuned!

Reference Link :- Android Developer Data Binding

Sample Code :-  GitHub Repository Link

 

Related Articles

#Tech

NHibernate, Linq and Lazy Collections

For the past few months we have been busy building a services framework for one of our clients so that they can build all of their enterprise web services without ever having to worry about the cross cutting concerns and... Read more
#Tech

Page Redirects using Spring.NET

Who is responsible for page redirects in ASPNET MVP – The View or the Presenter None of the above, it is you :) On a serious note, it is the View as one shouldn’t pollute the Presenter with the page navigation... Read more
  • Google user

    when will we get other parts?

  • Vikas Goyal

    Thank you for reading my blog. I am in the process of writing the second part. It should be out soon!