Click here to Skip to main content
15,867,704 members
Articles / Mobile Apps / Android

Android Binding - Introduction

Rate me:
Please Sign up or sign in to vote.
4.83/5 (26 votes)
1 Apr 2011LGPL37 min read 157.9K   84   25
An Introduction to a new Android-java based MVVM Presentation Framework

Introduction

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

Please also download from Market (Search "Markup Demo") the demo on most features of Android Binding.

A more fundamental, getting started to Android MVVM with android-binding tutorial series is up in my own blog.

UPDATE: v0.2 is released. Please visit the project homepage for details as it may not be compatible with previous versions.

Critical Changes (as of 30/1/2010)

If this is the first time you read this article, you may skip this section.

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 were made. Upon the release of 0.11, I suppose those changes should be final.

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.

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.

Observable<T> now requires passing the class of T as parameter: e.g.

Java
Observable<Boolean>(Boolean.class, true); 

Since this makes writing such code too verbose, some shorthand primitive observables are provided.

Sample Application

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

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

This sample is a modification based on Google's original Contact Manager Sample, the purpose of it is to show the differences 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:

Java
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 time for Android Binding to register and initialize the markup and binding providers, which can support custom view classes.

Activity

Activity is 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:

Java
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
<?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 the coming future). The binding namespace should point to http://www.gueei.com/android-binding/.

As shown in the 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 the later part of this article.

Also note 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 the layout of each item should look like.

Following is the contact_entry.xml:

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 bridges 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:

Java
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();
		}
	};

	private void populateContactList() {
            // Build adapter with contact entries
            Cursor cursor = getContacts();
            ContactList.setCursor(cursor);
        }

BooleanObservable is representing an object that is 'observable' by other objects, so, whatever changes are made on this object will keep its observers notified. There are quite some Observables defined in Android Binding, like StringObservable, IntegerObservable, ... all of them are subclasses of IObservable<T> which implement the following methods:

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

The get() and set() are 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 features 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 or CursorSource.

CursorSource takes two constructor parameters:

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 knows how to 'construct' the row. Let's look at them one by one.

Java
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 are 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 are 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:

Java
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. The above example is similar to a one-way converter, that converts the Id to a real contact.

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

Converter<?>

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

Indeed, Converter is a subclass of DependentObservable. It depends 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. You can go to the project homepage to download it.

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 briefly 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 in progress and this is my first OSS. I really look forward to comments and suggestions on this framework.

Author Blog and Project Details

License

This article, along with any associated source code and files, is licensed under The GNU Lesser General Public License (LGPLv3)


Written By
Hong Kong Hong Kong
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionHow can i add a button to the actiobar when i use the binding Pin
Member 1087732910-Jun-14 22:05
Member 1087732910-Jun-14 22:05 
QuestionNeed a start. A simple tutorial. Pin
Helmut Obertanner10-Feb-14 0:57
Helmut Obertanner10-Feb-14 0:57 
GeneralMy vote of 1 Pin
thefiloe16-May-13 23:45
thefiloe16-May-13 23:45 
GeneralVery helpful Pin
Bandi Ramesh16-Feb-13 0:37
Bandi Ramesh16-Feb-13 0:37 
QuestionMy vote of 5 Pin
Thanos7620-Jul-12 12:35
Thanos7620-Jul-12 12:35 
AnswerRe: My vote of 5 Pin
xandytsui20-Jul-12 14:22
xandytsui20-Jul-12 14:22 
GeneralRe: My vote of 5 Pin
Thanos7621-Jul-12 11:24
Thanos7621-Jul-12 11:24 
QuestionHelp with tabs and android-binding Pin
Member 887605224-Apr-12 0:42
Member 887605224-Apr-12 0:42 
Hi,

I'm trying to apply android-binding to a layout with tabs. I've used this code to create my layout:

http://code.google.com/p/android-binding/source/browse/trunk/AndroidBindingMarkupDemo/res/layout/tab.xml?r=428[^]

This is my activity's onCreate function:

Java
TaskListViewModel model = new TaskListViewModel(this);
this.setAndBindRootView(R.layout.prova, model);
Resources res = getResources();
TabHost tabs=(TabHost)findViewById(android.R.id.tabhost);
tabs.setup();

TabHost.TabSpec spec=tabs.newTabSpec("mitab1");
spec.setContent(R.id.calendarTab);
spec.setIndicator("Calendar",
        res.getDrawable(android.R.drawable.ic_btn_speak_now));
tabs.addTab(spec);
spec=tabs.newTabSpec("mitab2");
spec.setContent(R.id.listTab);
spec.setIndicator("List",
        res.getDrawable(android.R.drawable.ic_dialog_map));
tabs.addTab(spec);

tabs.setCurrentTab(0);


I want this code (or another code with the same goal) to be in my ViewModel so my Activity doesn't interact with my view. Is there any way to do it?

Thank you!
AnswerRe: Help with tabs and android-binding Pin
xandytsui24-Apr-12 1:24
xandytsui24-Apr-12 1:24 
QuestionAndroid binding Pin
ltn61422-Nov-11 21:52
ltn61422-Nov-11 21:52 
AnswerRe: Android binding Pin
xandytsui23-Nov-11 15:23
xandytsui23-Nov-11 15:23 
GeneralRe: Android binding Pin
ltn61423-Nov-11 15:30
ltn61423-Nov-11 15:30 
GeneralRe: Android binding Pin
xandytsui23-Nov-11 16:19
xandytsui23-Nov-11 16:19 
GeneralMy vote of 5 Pin
RobCroll2-Aug-11 3:13
RobCroll2-Aug-11 3:13 
GeneralMy vote of 5 Pin
Ashish Tyagi 408-Apr-11 23:09
Ashish Tyagi 408-Apr-11 23:09 
GeneralMy vote of 5 Pin
maq_rohit4-Mar-11 1:28
professionalmaq_rohit4-Mar-11 1:28 
GeneralRe: My vote of 5 Pin
xandytsui14-Apr-11 5:45
xandytsui14-Apr-11 5:45 
GeneralNice separation of concern - MVO5 Pin
Nic_Roche14-Jan-11 11:37
professionalNic_Roche14-Jan-11 11:37 
GeneralRe: Nice separation of concern - MVO5 Pin
xandytsui14-Jan-11 22:48
xandytsui14-Jan-11 22:48 
GeneralRe: Nice separation of concern - MVO5 Pin
Nic_Roche16-Jan-11 0:19
professionalNic_Roche16-Jan-11 0:19 
GeneralRe: Nice separation of concern - MVO5 Pin
xandytsui21-Jan-11 22:48
xandytsui21-Jan-11 22:48 
GeneralRe: Nice separation of concern - MVO5 Pin
Nic_Roche28-Jan-11 10:27
professionalNic_Roche28-Jan-11 10:27 
GeneralRe: Nice separation of concern - MVO5 Pin
xandytsui28-Jan-11 14:30
xandytsui28-Jan-11 14:30 
GeneralRe: Nice separation of concern - MVO5 Pin
xandytsui29-Jan-11 6:20
xandytsui29-Jan-11 6:20 
GeneralHaving written my own MVVM framework for WPF, I would just like to say... Pin
Sacha Barber12-Jan-11 2:28
Sacha Barber12-Jan-11 2:28 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.