Android custom ViewFactories


So it was three-hundred-twenty-four o’clock one night and I found myself up way past my bedtime trying to hack a custom ViewFactory in Android. Why would I do such a thing? What would I hope to gain? Why couldn’t I just go to sleep? Hi, I’m Cliff. You’re here because you lose sleep working through tough issues on Android. I’m here because I suffer from similar sleep depravation. Today we are going to discuss an unfamiliar, undocumented area of Android called ViewFactories. Disclaimer: I don’t  have any conclusive information on the topic; instead I am in exploratory mode learning as I go. You will not find answers or hidden gems in this article but check back in the future where I hope to have figured out more of the APIs.

We begin by asking the following question: what is a ViewFactory and why would anyone want to wrestle with one? I’m glad you asked. (Technically, I’m just glad you read me asking the question rhetorically.) A ViewFactory is an object that the Android LayoutInflator calls as it parses the layout xml files while inflating views. If you own a ViewFactory then you own an opportunity to add customization as Views are inflated. What can you do when views are inflated? I’m glad you asked that question as well! It brings me to my next topic, the MVVM pattern.

While reading up on the Model View ViewModel (MVVM ) pattern I discovered a tool that advertises easy implementation of the pattern on Android. The tool is called Robobinding and it provides an easy means of binding Java beans-like properties to your layout views as well as binding actions from those views to regular POJOs.  So where we are currently writing code like so:

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        setContentView(rootView);
        this.nameLabel = (TextView)
                findViewById(R.id.name_label);

        if (myPersonModel.getName() != null ) {
            nameLabel.setText(myPersonModel.getName());
        }
        this.nextButton = (Button) findViewById(R.id.next_button);
        ((Button) this.nextButton).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                myPersonModel.loadNextPerson();
                nameLabel.setText(myPersonModel.getName());
            }
        });
    }

Using Robobinding, you can add custom attrbutes to views in your layouts that automatically update and sync the view with properties in a Plain Old Java Object (POJO). You can also link view events such as onClick to arbitrary methods in your POJO.

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:bind="http://robobinding.org/android">
    <TextView
        bind:text="{name}" />
        ...
    <Button
        android:text="Next Person"
        bind:onClick="nextPerson"/>
</LinearLayout>
public class MainActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        ...
        View rootView = Binders.inflateAndBindWithoutPreInitializingViews(this, R.layout.activity_main, personModel);
        setContentView(rootView);
    }
}

What happens here is a custom attribute is added to a known Android view component and these attributes are used to identify properties and actions in the underlying presentation model which should be sync’ed with the view in question. The Activity includes logic that uses a Binders static class method to inflate the views while giving it a presentation model POJO that includes the name property and nextPerson action method. Most of this magic is achieved by using advanced Android concepts like Gradle plugins, AspectJ and Annotations. However, some of the magic happens in a custom ViewFactory. As the views are inflated these attributes are intercepted by special binding objects and used to add logic that reads/writes values from the POJO. That’s just a short description of what this fantastic framework does, but what I find interesting is the ViewFactory part.

I first learned about ViewFactories after hitting a bug with Robobinding that prevents it from working correctly with an AppCompatActivity or ActionbarActivity. That lead me to debugging the framework and walking into its code, which lead me to noticing a problem in how/when the ViewFactories are created in a regular Activity vs an AppCompatActivity, which lead me to rewriting the framework from scratch as an academic or exploratory exercise.

A ViewFactory is part of the Android framework used to create Android View objects from layout files. there is a chain of responsibility that I am beginning to understand where the a Factory can be combined with another ViewFactory in something called a Merger and these factories sometimes delegate to the underlying activity where the developer may want to add their own custom logic for inflating View objects. I don’t know too much beyond this.

What I can tell you now is that you cannot set the ViewFactory in an AppCompatActivity after calling onCreate() in the Activity base class. Instead you must set it before. Also, if you set the ViewFactory before calling Activity.onCreate() you may not be able to get a reference to the LayoutInflater. None of this makes much sense to me, again, I am just learning the APIs as I go along. Hopefully I’ll have more info in the coming days.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s