top 5 android m featuresWith the announcement of Android M at this year’s Google I/O conference, data binding becomes part of the developer’s tool set. With data binding, you create an ongoing link between an element in the user interface and a value (or a set of values). When a variable’s value is updated, the display on the user’s screen changes automatically. You don’t have to write code that explicitly updates the display. (More importantly, you can’t forget to write code that updates the display.)

During the Google I/O conference, I heard developers talking about “not having to call findViewById” and “not having to call setText.” It’s true that data binding eliminates the need for these method calls. But if you interpret “not having to call setText” as “saving you a line of code,” you’re missing the point. To eliminate only one or two setText calls (as I do in this article’s simple example), you must replace the calls with at least dozen new lines of code. The real power of data binding doesn’t come when you avoid one or two setText calls. It comes when the updating of a value occurs at many points in an app’s code. In that situation, the developer doesn’t have to keep track of all the ways a value can be updated. Instead, data binding creates a permanent tie between the data and the UI.

The official documentation on data binding is at https://developer.android.com/tools/data-binding/guide.html. The documentation has a few typos and (in my opinion) omits some useful details. So in this article I present the steps that I’ve taken to get a basic data binding example running. I also warn you about a few pitfalls that I met along the way. (All of this information is current as of June 10, 2015. Android’s beta’s change quickly. So I make no promises about the steps that you’ll be following at any later date.)

Step 1: Get Android Studio 1.3 beta.

You can get it at http://tools.android.com/download/studio/canary. Note that builds of Android Studio come via several channels — the stable channel, the beta channel, the dev channel, and the canary channel. In spite of being named “beta,” the 1.3 beta version of Android Studio isn’t available through the channel named “beta.” Instead, you download this version through the “canary” channel.

If you’re already running the canary version of Android Studio, you don’t have to visit the tools.android.com web site. When you launch Android Studio, you’ll be prompted to update to the 1.3 release.

Step 2: With Android Studio 1.3 running, open the Android SDK Manager to get the Android MNC Preview (the SDK for Android M) and the Android Support Repository (rev. 15 or later). Also open the Android AVD Manager to create an AVD that uses the Android M preview.

When I created this example, I had to experiment to find an Android M AVD that doesn’t stall when I try to run it. I tried several AVDs on my Mac with no luck. On Windows, I was able to get the x86_64 version running on a Nexus 6 skin. When the Android M preview emulator finally started up, it notified me that the SD card is damaged. I dismissed the notification with no ill results. Your results with the Android emulator will most certainly be different.

Step 3: Back in Android Studio’s main window (or the Android Studio Welcome screen) start a new phone/tablet project.

For the Minimum SDK select MNC: Android M (Preview). Otherwise, simply accept the defaults for creating a new project.

Step 4: Edit the new project’s code. Start by adding a dataBinder classpath dependency in the project’s build.gradle file. (See the boldface line below.)

// Top-level build file where you can add configuration options
// common to all sub-projects/modules.

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:1.3.0-beta1'
        classpath "com.android.databinding:dataBinder:1.0-rc0"

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}


allprojects {
    repositories {
        jcenter()
    }
}

Remember: A new Android Project has two build.gradle files — one for the project and one for the module within the project. The new com.android.databinding:dataBinder dependency belongs in the project’s build.gradle file.

Step 5: Add a few lines to the other build.gradle file (the module’s build.gradle file):

apply plugin: 'com.android.application'
apply plugin: 'com.android.databinding'

android {
    compileSdkVersion 'android-MNC'
    buildToolsVersion "21.1.2"

    defaultConfig {
        applicationId "com.example.androidm_project1"
        minSdkVersion 'MNC'
        targetSdkVersion 'MNC'
        versionCode 1
        versionName "1.0"
    }

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_7
        targetCompatibility JavaVersion.VERSION_1_7
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'),
                    'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
}

Once again, I’ve set the newly added lines in boldface type. All the other lines can remain as they were in the code that Android Studio generated. Of course, your project’s package name probably isn’t com.example.androidm_project2 as it is in my code. Just make sure that the SDK versions include the letters MNC.

When you use data binding, Android Studio generates some code that contains binary literals such as 0b1000L. So the project demands Java 7 rather than Java 6. That’s why, in the module’s build.gradle file, I added a compileOptions element to the project’s build.gradle file.

Step 6: Edit the app’s layout file.

In this very simple layout file, I’ve set only the interesting text in boldface:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
        <variable name="user" type="com.example.androidm_project1.User"/>
    </data>
    <LinearLayout
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <TextView android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{user.firstName}"/>
        <TextView android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{user.lastName}"/>
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="New Button"
            android:id="@+id/button"
            android:layout_gravity="left"
            android:onClick="onButtonClick"/>
    </LinearLayout>
</layout>

At the present time (early June 2015), Android Studio’s editor displays error markers on the <layout> start and end tags. But these error markers don’t prevent the app from running.

My simple layout file identifies several items:

  • A class named User

You’ll create User.java in the next step.

  • A field named user

You’ll declare this field in the app’s main activity.

  • Two TextView elements with special new android:text attributes

android-m-data-binding-fig1

These two android:text attributes begin the work of connecting text views with data values. If you look at the UI in Android Studio’s preview screen, you’ll see empty space where these text views normally appear.

  • A button whose click-handling method is named onButtonClick

I apologize to those who find the android:onClick attribute distasteful. If you’re one of these people, use an OnClickListener instead.

Step 7: Add this User class to your code (with the package declaration tweaked appropriately):

package com.example.androidm_project1;

import android.databinding.BaseObservable;
import android.databinding.Bindable;

public class User extends BaseObservable {
    private String firstName;
    private String lastName;

    public User(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

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

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

    public void setFirstName(String firstName) {
        this.firstName = firstName;
        notifyPropertyChanged(com.example.androidm_project1.BR.firstName);
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
        notifyPropertyChanged(com.example.androidm_project1.BR.lastName);
    }
}

The secret sauce in this User class code has two ingredients: the @Bindable annotations and the calls to notifyPropertyChanged.

When you first type this User class code, Android Studio’s editor might complain about the BR class name. You won’t have a generated BR.java file until you build the project, and you haven’t built the project yet. Eventually, you’ll have a BR.java file that looks something like this:

package com.example.androidm_project1;

public class BR {
    public static final int _all = 0;
    public static final int firstName = 1;
    public static final int lastName = 2;
    public static final int user = 3;
}

Step 8: Add lines to your app’s main activity.

This article’s main activity “swats a fly with a bulldozer.” It illustrates the simplest possible use of Android’s new data binding feature. Here’s the code:

package com.example.androidm_project1;

import android.app.Activity;
import android.databinding.DataBindingUtil;
import android.os.Bundle;
import android.view.View;
import android.widget.Toast;

import com.example.androidm_project1.databinding.ActivityMainBinding;

public class MainActivity extends Activity {
    User user;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ActivityMainBinding binding =
                DataBindingUtil.setContentView(this, R.layout.activity_main);
        user = new User("FirstName", "LastName");
        binding.setUser(user);
    }

    public void onButtonClick(View view) {
        Toast.makeText(this, "CLICKED", Toast.LENGTH_LONG).show();
        user.setLastName("NewLastName");
    }

}

You might see some error markers when you type this code. That’s because Android Studio doesn’t generate the ActivityMainBinding.java file until you build your project. Thus, the next step.

Step 9: In Android Studio’s main menu, choose Build->Make Project.

When the build is finished, the new 160 line ActivityMainBinding.java file contains a setUser method (a method that’s called in your activity’s onCreate method). In your project’s main activity, the call to this setUser method creates the last link in the chain between the user field’s data and the text in the UI.

Your project is ready for testing.

Step 10: Run the app and watch it work.

In the main activity, I make a click of the UI’s button change the value of the user object’s lastName field. (I call setLastName in the activity’s onButtonClick method.) When this happens, the automatically generated ActivityMainBinding class calls a setText method.

if ((dirtyFlags & 0b1101L) != 0) {
        this.mboundView2.setText(lastNameUser);
}

The setText method changes the text in the second text view on the device’s screen. android-m-data-binding-fig2-3

The screen is plain, but the underlying code is very cool.

Data binding has been available for a long time on many different platforms. But with Android M, this powerful feature makes its way into the Android developer’s bag of tricks.

Show 15 comments