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.
Android Binding 是一个为Android-Java提供xml布局视图绑定机制的开源框架。 它
Please also download from Market (Search "Markup Demo") the demo on most features of Android Binding.
你可以从Market(搜索“Markup Demo”)下载demo,这个demo使用了Android Bindding的大部分特性。
A more fundamental, getting started to Android MVVM with android-binding tutorial series is up in my own blog.
更基础的开始《Android MVVM 与android-binding 教程系列》已经上传至我的博客。
UPDATE: v0.2 is released. Please visit project homepage for details as it may not compatible with previous versions.
更新:v0.2已经发布。 更多细节请访问项目主页,它可能与以前的版本不兼容。
Critical Changes (as of 30/1/2010)
重要变化(到30/1/2010)
If this is the first time you read this article, you may skip this section.
如果这是你第一次看到这篇文章,你可以跳过这节
The version 0.11 of Android binding is released with this sample application. As the project evolves, a number of critical (yet would results breaking original codes) changes was made. Upon the release of 0.11 I suppose those changes should be final.
Android binding 0.11版与这个示例application一同发布。随着项目的演变,发生了一些关键的改变(将导致破坏以前的代码)。而在0.11发布时是假设这些改变是最终的。
In the first time I wrote this article, Android Binding doesn't support binding to object collections, but now, it can bind to Cursor or Array, each 'row' of the records are treated as a View Model, which means Command and DependentObservables are all functional, which would be covered later in this article.
在我第一次写这篇文章时,Android Binding 不支持绑定到集合对象,但是现在,它可以绑定到Cursor 或者Array, 记录的每一行被看作一个View Model,这意味着Command与DependentObservables 都是功能型的,它们将在本文的后面提及。
The sample application is rewritten, as the Contacts list no longer binds to the raw Adapter but via a more declarative way. Action related binding renamed to have a 'on-' prefix, for example, click -> onClick to make it more distinctive.
示例app已经被重写,因为联系列表不再绑定到原生Adapter上,而是而是通过一种更可描述性的方式。 与绑定有关的动作被重命名,添加了一个“on”前缀,例如, click->onClick 以使它更好区分。
Observable<T> now requires passing the class of T as parameter: e.g. Observable<Boolean>(Boolean.class, true);
现在Observable<T>需要传递class T作为参数,例如Observable<Boolean>
Since this makes writing such code too verbose, some shorthanded primitive observables are provided.
因为这样使得编写这些代码过于繁琐, 提供了一些简短的observables
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/downloads/list
and the compiled application is available at Android Market (Search "Android Binding" in Market).
下面将简要介绍怎样使用它。 本例中使用的示例app源码可以在http://code.google.com/p/android-binding/downloads/list 获取。
编译过的app可以在Android Market (在Market里搜索“Android Binding”)下载。
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.
这个示例是在Google原先的Contact Manager示例的基础上修改而来, 目的是为了演示view 绑定区别以及使用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(this);
}
}
The Binder.init(Application)
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="http://schemas.android.com/apk/res/android"
xmlns:binding="http://www.gueei.com/android-binding/"
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:itemSource="ContactList"
binding:itemTemplate="@layout/contact_entry"
android:layout_weight="1"/>
<CheckBox android:layout_width="wrap_content"
android:layout_height="wrap_content"
binding:checked="ShowInvisible"
binding:onCheckedChange="PopulateList"
android:text="@string/showInvisible"/>
<Button android:layout_width="fill_parent"
android:layout_height="wrap_content"
binding:onClick="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). The binding namespace should point to "http://www.gueei.com/android-binding/".
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.
Also notes that for the ListView, it is binding to itemSource
which will be either some Cursor or Array of View Models (and we will cover that later) and the itemTemplate
is a standard Android Resource reference format, that tells what is the layout of each item should looks like.
Following is the contact_entry.xml
:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:binding="http://www.gueei.com/android-binding/"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
binding:onClick="ShowContact"
>
<TextView android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="20dip"
binding:text="Name"
/>
</LinearLayout>
It is still fairly standard layout xml file with customized binding namespace. Notice that the layout root (i.e. the LinearLayout) defined an action onClick
.
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:

<p style="margin: 0px; font: 11px Monaco;">public class ContactManagerModel {
private Activity mContext;
public CursorSource<ContactRowModel> ContactList =
new CursorSource<ContactRowModel>
(ContactRowModel.class, new Factory());
public BooleanObservable ShowInvisible = new BooleanObservable(false);
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();
}
};
</p><p style="margin: 0px; font: 11px Monaco;">
</p><p style="margin: 0px; font: 11px Monaco;"> private void populateContactList() {
// Build adapter with contact entries
Cursor cursor = getContacts();
ContactList.setCursor(cursor);
}
</p>
BooleanObservable
is representing an object that is 'observable' by other objects, so, whatever changes made on this object will let it's observers notified. There are quite some Observables defined in Android Binding, like StringObservable, IntegerObservable... all of them are subclasses of IObservable<T> which implements following methods
- set()
- get()
- 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.
Finally, since our contact source is a cursor, we need to supply the CursorSource<?> to indicate how our Cursor is used.
Binding to Cursor
In Android Binding, each row of record in the Cursor, is supposed to be a View Model. That means, you are applying the same layout each with a separate set of data. One of the most powerful feature in Android Binding, is that it allows you to define Commands and more complicated logic even in the sub-view models. As mentioned before, you cannot just supply a Cursor as itemSource
for AdapterViews (including ListView, Spinners...), but it must be either an ArraySource
orCursorSource
.
CursorSource takes two constructor parameters:

<pre lang="java">public CursorSource<ContactRowModel> ContactList =
new CursorSource<ContactRowModel>
(ContactRowModel.class, new Factory());
First one, is the class of the sub-viewmodel that representing each 'row' of cursor data(so it is named rowModel), the other one, is a factory that actually know how to 'construct' the row. Let's look at them one by one.

public class ContactRowModel extends CursorRowModel {
public IdField Id = new IdField(0);
public StringField Name = new StringField(1);
public Command ShowContact = new Command(){
//...
The RowModel is pretty much standard View Model, except it requires to extend from CursorRowModel. The IdField
,StringField
is simply Observables but their value will be filled up automatically using the Cursor; the number within the bracket tells which column you are mapping that field to.
Model Validation
Model validation (to be precise, validating the View Model) is also supported, this is also demonstrated in this sample application but you may read my other article for details.
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>(Contact.class, 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
An Alpha version of the Project is released. Which you can go to the project homepage to download.
Future plan is to add support to more POJO (Plain Old Java Object) way of View Model declaration.
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/
License
This article, along with any associated source code and files, is licensed under The GNU Lesser General Public License (LGPLv3)
About the Author
xandytsui |