Introduction

Android Binding is a new Open Source Framework for Android-Java providing xml layout view binding mechanism. It helsp development of Android Application by decoupling the View widgets and backend Activities. It is best work with MVP or MVVM patterns.

Sample Application

Following will briefly introduce how it is used. Where the sample application codes used here is obtainable at:

http://code.google.com/p/android-binding/source/browse/#svn%2FDemos%2Ftrunk%2FContactManagerDemo

and the compiled application is available at Android Market (Search "Android Binding" in Market).

This sample a modification based on Google's original Contact Manager Sample, the puropose of it is to show the different in view binding and the benefits of using Android Binding.

Basic Configuration

To use Android Binding, all you need to do is to reference the library (in Eclipse, right click project -> Properties -> Android, reference the Android Binding Project as library). And then, in Application class:

public class ContactManagerApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        Binder.init();
    }
}

The Binder.init() is required to run once and only once, across the application life cycle. During the init() process, it is the time for Android Binding to register and initialize the markup and binding providers, which can support custom view classes.

Activity

Activity no longer required to be View-awared, even the view model doesn't. Android Binding is best supported for View Model First development in MVVM. So, no more presentation / user interaction logic in Activity and results in a clean Activity class:

public final class ContactManager extends Activity
{
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        ContactManagerModel model = new ContactManagerModel(this);
        Binder.setAndBindContentView(this, R.layout.contact_manager, model);
    }
}

You provide the Model (or ViewModel to be precise) to binder, and it automatically wires up the view with the ViewModel. This is how we markup the contact_manager.xml:

Layout

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android= href="http://schemas.android.com/apk/res/android">http://schemas.android.com/apk/res/android
              xmlns:binding="http://schemas.android.com/apk/res/com.gueei.demo.contactmanager">http://schemas.android.com/apk/res/com.gueei.demo.contactmanager"
              android:orientation="vertical"
              android:layout_width="fill_parent"
              android:layout_height="fill_parent">
    <ListView android:layout_width="fill_parent"
              android:layout_height="wrap_content"
              binding:adapter="ContactList"
              binding:clickedId="SelectedContactId"
              binding:itemClicked="ViewContact"
              android:layout_weight="1"/>
    <CheckBox android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              binding:checked="ShowInvisible"
              binding:checkedChange="PopulateList"
              android:text="@string/showInvisible"/>
    <Button android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            binding:click="AddContact"
            android:text="@string/addContactButtonLabel"/>
</LinearLayout>

Layout looks pretty much the same as standard Android Layout, except that an extra binding namespace is imported. There's an issue with AAPT, that the binding namespace needed to reference to the "demo" project instead of the library. (Hope it can be solved in coming future).

As shown in above layout file, the markup is done through the custom namespace (prefixed binding), and the attribute is pretty much reflecting to most original View attributes.

There are currently two kinds of bindable objects in a view. First is the Property (like checked in CheckBox) and the second is Command (checkedChange in Checkbox), where both of them will be explained in later part of this article.

ViewModel

The ViewModel is something that bridge the View and Model (it will be the contact provider in this example). The ViewModel in Android Binding is a class defining all the 'bindable' data/command Fields for the View to access. Following shows a portion of the ViewModel:

public class ContactManagerModel {
 private Activity mContext;
 public Observable<Adapter> ContactList = new Observable<Adapter>();
 public Observable<Boolean> ShowInvisible = new Observable<Boolean>(false);
 public Observable<Long> SelectedContactId = new Observable<Long>(0l);
 public Command ViewContact = new Command(){
  public void Invoke(View view, Object... args) {
   Long x = SelectedContactId.get();
   toastContact(x.toString());
  }
 };
 
 public Command PopulateList = new Command(){
  public void Invoke(View view, Object... args) {
   populateContactList();
  }
 };
 public Command AddContact = new Command(){
  public void Invoke(View view, Object... args) {
   launchContactAdder();
  }
 };
 
 public ContactManagerModel(Activity context){
  mContext = context;
  populateContactList();
 }
//...
}

Observable<?> is the base class for any property that is bindable to the view, it defines three important public methods:

  1. set()
  2. get()
  3. notifyChanged()

The get() and set() is a replacement for getter and setter methods in java, which will, by default, notify the subscribers about the change on the object automatically. (Where this is a borrowed concept from .Net).

Command is the interface that defines something that is "Executable". Normally they will be wired with Event fired from User Interface.

Furthermore

Observable is quite restricted at the moment, as it requires the View Attribute and the Property of Model to be the same in type. That means, if you bind the checked (which is boolean) attribute with an Observable<Integer>, it won't work, since implicit type casting is not allowed. Therefore, another two subclasses of Observable is provided:

DependentObservable<?>

This denotes that an observables' value is dependent on other Observables. For example, we can rewrite the above ViewModel to add an SelectedContact

DependentObservable<Contact> SelectedContact = new
      DependentObservable<Contact>(SelectedId){
         @Override
         public Contact calculateValue(Object... args){
            getContactFromDb((Integer)args[0]);
        }
    };

DependentObservable requires only one override method, the calculateValue. Since DependentObservable can depends on multiple dependents, the parameters length in calculateValue is open, and explicit typecast is required. Above example is similar to a one-way converter, that converts the Id to a real contact.

There's actually Converter class in Android Binding, and the only difference with DependentObservable is that Converter can allow two-way binding:

Converter<?>

public abstract void ConvertBack(T value, Object[] outResult);

Indeed, Converter is a subclass of DependentObservable. It is depending on a list of other observables, it can convert a boolean true to number 1, and when the convert back when other changes the convert's value.

Progress and plans

The project is still in pre-alpha and not stable enough as a release. But more sample/example projects are building along with polishing the main library are underway.

Planning to include a Model Validation framework, where the view is capable of displaying model errors.

You are free to download the code from the Google Code project repository, reports and issues please drop in the Discussion Group: http://groups.google.com/group/androidbinding

Conclusion

This article breifly introduces the functionality of the Android Binding. If you compare it to the original Contact Manager Sample, you will find that using Android Binding w/MVVM results in much cleaner code and thus, more friendly to Unit testing and better code quality. Active development is undergoing and this is my first OSS. I really look forward to comments and suggestions on this framework.

Author

Andy Tsui

Blog: http://andytsui.wordpress.com

Discussion on project: http://groups.google.com/group/androidbinding

Project hosting: http://code.google.com/p/android-binding/

推荐.NET配套的通用数据层ORM框架:CYQ.Data 通用数据层框架