In this tutorial we’ll look into some other tricky usages of Data Binding in our application. For a better understanding of this tutorial, do view the Android Data Binding Tutorial.
Android Data Binding Recap
In the previous tutorial we looked into how Data Binding approach removes the need of using findViewById to hookup the UI view objects in our app code.
Another advantage of Data Binding over findViewById is that it enhances the performance of the application.
Using findViewById requires us to lookup the view in the entire hierarchy every time it’s invoked. Thus it requires a single pass through the entire view hierarchy for every child view. On the other hand, Data Binding uses just one single pass and stores all the field names of every child view layout. There’s no need for a second pass since we’ve already found all the views in the first pass itself.
Android Data Binding Overview
Data Binding has lots more to do than just getting rid of findViewById. You must have experienced scenarios where a ListView or a RecyclerView or just a normal layout for the sake uses a data model to add the relevant information into the layout. Even if we get the field names of the view layouts in our MainActivity it still requires us to write a lot of repetitive code snippets. Let’s say we have a layout where we’re adding data from a DataModel.java class dynamically and updating the values after a specific interval. The following code snippet shows an example implementation of Data Binding when the data is supplied to the layout from a Data Model class.
activity_main.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
<layout xmlns:android="https://schemas.android.com/apk/res/android"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <ImageView android:id="@+id/imageView" android:layout_width="wrap_content" android:layout_height="wrap_content"/> <TextView android:id="@+id/name" android:layout_width="wrap_content" android:layout_height="wrap_content"/> <TextView android:id="@+id/summary" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </LinearLayout> </layout> |
The DataModel.java class is given below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
public class DataModel { String name; int image; String summary; public DataModel(int image, String name, String summary) { this.name = name; this.summary = summary; this.image = image; } public int getImage() { return image; } public void setImage(int image) { this.image = image; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getSummary() { return summary; } public void setSummary(String summary) { this.summary = summary; } } |
The MainActivity.java is given below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
public class MainActivity extends AppCompatActivity { ActivityMainBinding binding; Timer timer; int i = 0; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); binding = DataBindingUtil.setContentView(this, R.layout.activity_main); DataModel dataModel = new DataModel(R.drawable.marsh, "Android MarshMallow", "Android 6.0"); binding.imageView.setImageResource(dataModel.getImage()); binding.name.setText(dataModel.getName()); binding.summary.setText(dataModel.getSummary()); timer= new Timer(); timer.scheduleAtFixedRate(new TimerTask() { @Override public void run() { runOnUiThread(new Runnable() { @Override public void run() { if (i == 0) { DataModel dataModel = new DataModel(R.drawable.lollipop, "Android Lollipop", "Android 5.0"); binding.imageView.setImageResource(dataModel.getImage()); binding.name.setText(dataModel.getName()); binding.summary.setText(dataModel.getSummary()); i=1; } else { i=0; DataModel dataModel = new DataModel(R.drawable.marsh, "Android MarshMallow", "Android 6.0"); binding.imageView.setImageResource(dataModel.getImage()); binding.name.setText(dataModel.getName()); binding.summary.setText(dataModel.getSummary()); } } }); } }, 3000, 3000); } } |
We’ve used a timer that keeps changing the layout data alternately after every 3 seconds.
As you can see there is too much repetitive code for setText and setImageResource.
DataBinding allows us to directly assign the data from the DataModel class inside our xml layout. We’ll see how.
Android Data Binding Project Structure
Android Data Binding Code
We define the DataModel class variable object in the xml as shown in the layout below.
activity_main.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
<?xml version="1.0" encoding="utf-8"?> <layout xmlns:android="https://schemas.android.com/apk/res/android"> <data> <variable name="data" type="com.journaldev.advanceddatabinding.DataModel" /> </data> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:orientation="vertical"> <ImageView android:id="@+id/imageView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="https://www.journaldev.com/11950/@{data.image}" /> <TextView android:id="@+id/name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{data.name}" /> <TextView android:id="@+id/summary" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{data.summary}" /> </LinearLayout> </layout> |
DataBinding has its own expression language for layout files. It allows us to assign the data directly in the xml attributes.
The MainActivity.java is given below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
public class MainActivity extends AppCompatActivity { ActivityMainBinding binding; Timer timer; int i = 0; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); binding = DataBindingUtil.setContentView(this, R.layout.activity_main); DataModel dataModel = new DataModel(R.drawable.marsh, "Android MarshMallow", "Android 6.0"); binding.setData(dataModel); timer = new Timer(); timer.scheduleAtFixedRate(new TimerTask() { @Override public void run() { runOnUiThread(new Runnable() { @Override public void run() { if (i == 0) { DataModel dataModel = new DataModel(R.drawable.lollipop, "Android Lollipop", "Android 5.0"); binding.setData(dataModel); i = 1; } else { i = 0; DataModel dataModel = new DataModel(R.drawable.marsh, "Android MarshMallow", "Android 6.0"); binding.setData(dataModel); } } }); } }, 3000, 3000); // End of your timer code. } @BindingAdapter({"android:src"}) public static void setImageViewResource(ImageView imageView, int resource) { imageView.setImageResource(resource); } } |
Doesn’t it look a lot cleaner and more readable now!
Few inferences drawn from the above code:
Android Data Binding App Output
The output of the application in action is given below.
The expression language provided by DataBinding has much more to use than just specifying the data.
We can specify the xml attributes based on certain conditions as shown below.
1 2 3 |
android:text="@{data.name != null ? data.name : data.summary}" |
The above line can be be written in a more compact form:
1 2 3 |
android:text="@{data.name ?? data.summary}" |
This brings an end to this tutorial. You can download the Android AdvanceDataBinding Project from the below link.