UI Framework Comparison: Data Binding

Most UI frameworks for native mobile development are now based on a specific language, a DSL, to build the User Interface. This could be compared to HTML for the web developers. Each of them have a different approach which is interesting to compare.

Declaration of the UI

Android and Microsoft made the choice of xml. A well known format but quite verbose.

1
2
3
4
5
6
7
8
9
10
11
<RelativeLayout
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:background="@drawable/bg_distance">


<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/bold_10_standard_less"/>


</RelativeLayout>

While QT prefers a more declarative syntax similar to the first JavaFx Script. Here a example with the qt-cascade framework:

1
Container {
    verticalAlignment: VerticalAlignment.Center
    ImageView {
        id: tIDBall
        verticalAlignment: VerticalAlignment.Center
        horizontalAlignment: HorizontalAlignment.Center
    }
}

And Tizen proposes a piece of xml that can only be generated by a WYSIWYG (which was quite buggy by the way) :

1
2
3
4
5
6
7
8
<ScenePanel Bversion="2.0.0.201307161753" Dversion="20120315">
<LogicalCoordinate>720</LogicalCoordinate>
<Panel id="CUSTOM_ITEM_RECIPE">
<property backgroundColor="" backgroundColorOpacity="0" compositeEnabled="true" groupStyle="GROUP_STYLE_NONE"/>
<layout height="130.0" mode="Portrait" type="LAYOUT_RELATIVE" width="720.0" x="0.0" y="0.0"/>
<layout height="300.0" mode="Landscape" type="LAYOUT_RELATIVE" width="93.0" x="0.0" y="0.0"/>
</Panel>
</ScenePanel>

The greatest advantage of these DSL is a cleaner code, since the UI is separated from the behaviour and from the logic code.
Just take a look at an old J2ME code, where all aspects of the interface are built with pure Java code:

1
2
3
4
5
6
7
8
9
10
public LoginScreen() {
super();
add(new CustomTextField(17, Utils.GREY_TEXT, "Title", 10));

loginForm = new FormManager(TableLayoutManager.USE_ALL_WIDTH);
loginForm.add(new TextForm("login", Local.get(Local.FORM_EMAIL), "", TextForm.TYPE_MAIL).setMandatory(true));
loginForm.add(new PasswordForm("password", Local.get(Local.FORM_PASSWORD), "").setMandatory(true));
loginForm.setPadding(5, 10, 5, 10);
add(loginForm);
}

Feeding the data

Now that the UI is written inside the DSL, it becomes more difficult to access it from the code. The dev has to find the view, inject the dynamic data to it and then code the behaviour like hiding a view, animating, activate on click, …

Android’s native solution consists of giving ids to the views, which are put into an id catalog, the famous R file. Then the dev may find the view with the id:

1
2
3
4
5
public void onResume(){
super.onResume();
TextView title = (TextView) getActivity().findViewById(R.id.title_text);
title.setText(R.string.myTitle);
}

Html/Javascript provides a similar solution, greatly improved by the powerful selector:

1
$('#errorLayout h3').text("error title");

Finding ids quickly become too verbose and tedious on Android. That’s why some guys added annotations library, which saves some line of code:

1
2
3
4
5
6
7
@InjectView(R.id.title_text) 
EditText title;

public void onResume(){
super.onResume();
title.setText(R.string.myTitle);
}

Data-Binding

But recently, Android announced the support of the data-binding pattern. What is that?
This is a very common practice for Windows or Qml developers that allows to write less code, to highly reduce the code dependency, to ease the development in team, …

Have a look at this Windows 10 XAML binding on WPF framework:

1
<TextBlock 
    Text="{Binding User.Name}"
/>

The text is directly binded to a model’s value. Its sounds great but the dev loose the flexibility to manipulate the data.
WPF has a solution with the converter. We can expose converter classes to transform a value to another. Useful if you want, for instance, to convert a boolean to a visibility:

1
<TextBlock 
    Visibility="{Binding User.Security.NameIsPublic, Converter={StaticResource BoolToVisibilityConverter}}" 
    Text="{Binding User.Name}"
/>

But sometimes we need a more complex data transformation, for instance a string composition or a visibility of a view relative to a non-trivial logic.
To achieve this, we can bind to multiple values with a logic, or expose a fake data and bind to it:
(ps: Multiple binding is not always available “thanks” to the restriction of the Windows Store app)

1
<TextBlock 
    Text="{Binding PriceText}"
/>

public string PriceText {
    get {
        if(Price != null){
            return $"It costs {Price} {Currency}"
        }
        return "Not for sell";
    }
}

In another world, the QT one, QML found a way to keep an high flexibility by providing a full language to bind with, the javascript. It reduces the declarative aspect for a gain a power.
We can even write an entire application in qml/Javascript similar to html/Javascript:

1
Container {
    topPadding: isWide ? 24 : 12
    layout: StackLayout {
        orientation: Qt.trManager.isRTL ? LayoutOrientation.RightToLeft : LayoutOrientation.LeftToRight
    }

    ImageView {
        imageSource: "asset:///images/" + ListItemData.news_image
    }
}

By reading android documentation, It feels like they made a mixed choice. They have converters but still provide a minimal dynamism with logical and mathematical operators (or, and, …) and calls to a function, directly in the xml.

The risk of DataBinding

Yes the code is cleaner, loosely coupled, less verbose, easier to maintain, easier to unit-test…

But with the weak coupling also comes bugs harder to investigate.
To debug a binding that is not working as expected, one should have a good knowledge of the code to understand the data affectation.

Particularly for the new data-binding system of Android. While Windows forces a declarative syntax, Android would propose a thousand way to code the same thing.
Should we choose a converter, a call to a method, directly write the code with xml logic or add a fake field in the model class, … A project will require a good “Best practice” to guide the developers on the same path.