Android, Dependency Injection (IOC) with roboguice and MVVM (Model-View-ViewModel) pattern

If you’re working with .NET, maybe you’re already familiar with the concepts of dependency injection and MVVM (Model-View-ViewModel) pattern. Some of popular dependency injection containers for .NET are Castle Windsor, Ninject or Unity… They are all good frameworks, it just depends on which you prefer. For example, I use Castle Windsor at company and Ninject at home so that I can understand and use both of frameworks. It’s just the matter of favorite. The MVVM pattern was introduced years ago when WPF came to market. This pattern makes use of data binding structure of WPF and helps programmer to separate the view completely from logic layer. For more details about this pattern you can read some articles on my site about MVVM. Today, I will discuss again about these concepts, however not for .NET application, but I would like to show how we can apply these concepts into Android app. The example I use in this post is a De-De-Dictionary app. In this app, I can add German vocabulary with his explanation (also in German :)) through a user interface or look up for a vocabulary. Nothing special than a real dictionary book.

I. Dependency Injection

First part of this post is about Dependency Injection. If you make a search in Internet about dependency injection for Android, you’ll get some candidates for IOC such as dagger, roboguice, transfuse,… Just take look at all of them and find the best yourself. I, myself, prefer roboguice the most. It’s easy to integrate, to use and his workflow is much more likely IOC in .Net. Therefore I will use roboguice in this example. Now let’s start to integrate roboguice into project.

1. Download the following .jar files to libs folder of your project
http://repo1.maven.org/maven2/org/roboguice/roboguice/2.0/roboguice-2.0.jar
http://repo1.maven.org/maven2/com/google/inject/guice/3.0/guice-3.0-no_aop.jar
http://repo1.maven.org/maven2/com/google/code/findbugs/jsr305/1.3.9/jsr305-1.3.9.jar
http://hintdesk.com/Web/Source/javax.inject-1.jar

2. Add reference to them (if you use Intellij IDEA, you can read instructions at Intellij IDEA FAQ to add them as reference).

3. Create a new class extending Application class in Android and override the onCreate() function

public class IOCApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();    //To change body of overridden methods use File | Settings | File Templates.
        RoboGuice.setBaseApplicationInjector(this, RoboGuice.DEFAULT_STAGE, RoboGuice.newDefaultRoboModule(this), new IOCModule());

    }
}

In the code listing above, we initialize roboguice by telling him that he should use 2 modules for finding dependency objects and inject them during runtime. The first one is the default one of roboguice. We need it for injecting view, resource, system service… and other Android’s things. The second one IOCModule() is our module. In this one, we’ll define how our custom dependency objects should be resolved

public class IOCModule implements Module {
    @Override
    public void configure(Binder binder) {
        binder.bind(IMainActivityViewModel.class).to(MainActivityViewModel.class);
        binder.bind(IWordDAO.class).to(WordDAO.class);
        binder.bind(IAddWordActivityViewModel.class).to(AddWordActivityViewModel.class);
    }
}

In my example,I have 2 dependency ViewModels and one DAO class. The ViewModel classes reflect how the view looks like and handles business logic. The DAO class is where I hold data from database or write them back to database. For now, just don’t care about viewmodel or DAO class. What important is, at this module, we’re defining how components should be injected. The interface IMainActivityViewModel should be instantiated with class MainActivityViewModel, interface IWordDAO with WordDAO and IAddWordActivityViewModel with AddWordActivityViewModel.

4. We have defined roboguice modules for registering components. Now we have to talk Android to load our dependency injections at start up. Go to AndroidManifest.xml, add an attribute android:name to application node with value of IOCApplication package name like following

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
 package="com.hintdesk.De_De_Dict"
 android:versionCode="1"
 android:versionName="1.0">
 <uses-sdk android:minSdkVersion="17"/>
 <application android:label="@string/app_name" android:icon="@drawable/ic_launcher" android:name="com.hintdesk.De_De_Dict.infrastructure.IOCApplication">
 <activity android:name="MainActivity"
 android:label="@string/app_name">
 <intent-filter>
 <action android:name="android.intent.action.MAIN"/>
 <category android:name="android.intent.category.LAUNCHER"/>
 </intent-filter>
 </activity>
 <activity android:name=".view.AddWordActivity"/>
 </application>
</manifest>

5. Now, go back to our Activity, make it extending RoboActivity class and let’s rock with the injection

public class MainActivity extends RoboActivity {

    @InjectView(R.id.autoCompleteTextView) private AutoCompleteTextView autoCompleteTextView;
    @InjectView(R.id.imageButtonSearch) private ImageButton imageButtonSearch;
    @InjectView(R.id.textViewName) private TextView textViewName;
    @InjectView(R.id.textViewType) private TextView textViewType;
    @InjectView(R.id.textViewMeaning) private TextView textViewMeaning;
    @InjectView(R.id.textViewSynonym) private TextView textViewSynonym;
    @InjectView(R.id.textViewExample) private TextView textViewExample;

    @Inject private IMainActivityViewModel viewModel;
...
}

So, as you can see, we don’t need to call any findViewById() to get component from view. Everything was resolved through injection. You can immediately use injected components such as loading data to it or handling click event

private void initializeComponent() {
	viewModel.setContext(this);
	ArrayAdapter arrayAdapter = new ArrayAdapter(this,android.R.layout.simple_list_item_1,viewModel.getWords());
	autoCompleteTextView.setAdapter(arrayAdapter);
	imageButtonSearch.setOnClickListener(imageButtonSearchOnClickListener);
}

then you’ll get all benefits of dependency injection : The primary purpose of the dependency injection pattern is to allow selection among multiple implementations of a given dependency interface at runtime, or via configuration files, instead of at compile time. The pattern is particularly useful for providing stub test implementations of complex components when testing, but is often used for locating plugin components, or locating and initializing software services.
Unit testing of components in large software systems is difficult, because components under test often require the presence of a substantial amount of infrastructure and set up in order to operate at all. Dependency injection simplifies the process of bringing up a working instance of an isolated component for testing. Because components declare their dependencies, a test can automatically bring up only those dependencies required to perform testing.
More importantly, injectors can be configured to swap in simplified stub implementations of sub-components when testing, the idea being that the component under test can be tested in isolation as long as the substituted sub-components implement the contract of the dependent interface sufficiently to perform the unit test in question.
As an example, consider an automatic stock trading program that communicates with a live online trading service and stores historical analytic data in a distributed database. To test the component which recommends trades, one would ordinarily need to have a connection to the online service and an actual distributed database suitably populated with test data. Using dependency injection, the components that provide access to the online service and back-end databases could be replaced altogether with a test implementation of the dependency interface contracts that provide just enough behavior to perform tests on the component under test.
(From Wikipedia)

If you want to know more about roboguice, you can take a look at its wiki site https://github.com/roboguice/roboguice/wiki.

II.MVVM (Model-View-ViewModel)

Now we reach second part of this post, in this part, I will show how I can partially apply MVVM in Android. I would like to emphasize that I can only partially use MVVM in Android because data bindings in Android don’t work bidirectionally like in .NET. We can load data source for a component but any changes in that data source won’t be invoked back into “property”. We have to do as traditional way with handling events and then getting current data. A normal MVVM pattern has format as image below

MVVM pattern

where:
Data bindings:
– .NET: is the bridge between a property in ViewModel and a property of UI component
or a command between a function in ViewModel and an event of UI component. These bridge will be automatically built, we don’t have to handle any event.
– Android: we have to load data from property of ViewModel into component (by calling setAdapter for Spinner/AutoCompleteTextView or setText for TextView) and read value back from UI component to property (by calling getSelectedItem() or getText())
DAO:
are the classes responsible for loading data from database and give it to ViewModel or receive data from ViewModel and write data back into database.
ORM:
is Object-Relation-Mapping framework such as EntityFramework, NHibernate in .NET. In Android maybe ORMLite is a good candidate.
ViewModel:
as I mentioned above, will reflect how the view looks like and handle all business logic.

Let’s take a look at my example to better understand the pattern. The MainActivity is where I show the information of a vocabulary.

MainActivity

There are 1 AutoCompleteTextView,1 ImageButton, 5 TextView for Meta-data of a vocabulary. That means the viewmodel must reflect all of these information

ViewModel reflection

The image above shows exactly what MVVM means. For AutoCompleteTextView, we need to reflect the list of suggested vocabularies and the current vocabulary entered by user. For ImageButton, we need to handle the action search when user clicks on that button to look up a vocabulary. For the rest, we need to reflect the current look-up-vocabulary to show all other information of a vocabulary. That means, all of what user can see, can touch or how data should be displayed, must be defined in ViewModel layer.

public class MainActivityViewModel implements IMainActivityViewModel {
    @Inject
    private IWordDAO wordDAO;

    private String lookUpWord;

    @Override
    public List<String> getWords() {
        List<String> result = new ArrayList<String>();
        for (Word word : wordDAO.loadAll()) {
            result.add(word.getName());
        }
        return result;
    }

    @Override
    public void setContext(Context context) {
        wordDAO.setContext(context);
    }

    @Override
    public void search() {
       return wordDAO.load(lookUpWord);
    }

    public void setLookUpWord(String lookUpWord) {
        this.lookUpWord = lookUpWord;
    }

    @Override
    public Word getCurrentWord() {
        return wordDAO.load(lookUpWord);
    }
}

When you go further by studying the implementation of ViewModel, you’ll see how business logic action is executed and how the lower layer will be called. In my example, the DAO class comes in to use in ViewModel layer for any CRUD (Create, Read, Update,Delete) action. Please take a note that, my DAO classes are also injected. I do not initialize them at all, I use interface everywhere, never a concrete class. I don’t use any ORM in my example, therefore I have to map object manually. If you dig deeper in the code, you’ll see how I construct my own “ugly” ORM.

public class WordDAO extends BaseDAO implements IWordDAO {
    @Override
    public List<Word> loadAll() {
        List<Word> result = new ArrayList<Word>();
        Cursor cursor = loadAll(Word.TABLE, Word.COLUMNS);
        if (cursor.moveToFirst()) {
            do {
                Word word = new Word();
                word.setID(cursor.getInt(cursor.getColumnIndex(Word._ID)));
                word.setName(cursor.getString(cursor.getColumnIndex(Word.NAME)));
                word.setType(WordType.valueOf(cursor.getString(cursor.getColumnIndex(Word.TYPE))));
                word.setPlural(cursor.getString(cursor.getColumnIndex(Word.PLURAL)));
                word.setMeaning(cursor.getString(cursor.getColumnIndex(Word.MEANING)));
                word.setSynonym(cursor.getString(cursor.getColumnIndex(Word.SYNONYM)));
                word.setExample(cursor.getString(cursor.getColumnIndex(Word.EXAMPLE)));
                result.add(word);
            }
            while (cursor.moveToNext());
        }
        cursor.close();
        return result;
    }

    @Override
    public Word load(String name) {
        String selection = "NAME = ?";
        String[] args = {name};
        Cursor cursor = loadAll(Word.TABLE, Word.COLUMNS, selection, args);

        Word word = null;
        if (cursor.moveToFirst()) {

            word = new Word();
            word.setID(cursor.getInt(cursor.getColumnIndex(Word._ID)));
            word.setName(cursor.getString(cursor.getColumnIndex(Word.NAME)));
            word.setType(WordType.valueOf(cursor.getString(cursor.getColumnIndex(Word.TYPE))));
            word.setPlural(cursor.getString(cursor.getColumnIndex(Word.PLURAL)));
            word.setMeaning(cursor.getString(cursor.getColumnIndex(Word.MEANING)));
            word.setSynonym(cursor.getString(cursor.getColumnIndex(Word.SYNONYM)));
            word.setExample(cursor.getString(cursor.getColumnIndex(Word.EXAMPLE)));

        }
        return word;
    }

    @Override
    public void saveOrUpdate(Word word) {
        ContentValues contentValues = new ContentValues();
        contentValues.put(Word.NAME, word.getName());
        contentValues.put(Word.TYPE, word.getType().name());
        contentValues.put(Word.PLURAL, word.getPlural());
        contentValues.put(Word.MEANING, word.getMeaning());
        contentValues.put(Word.SYNONYM, word.getSynonym());
        contentValues.put(Word.EXAMPLE, word.getExample());
        if (word.getID()<=0)
            insert(Word.TABLE, contentValues);
        else
        {
            String selection = "_ID = ?";
            String[] args = {Integer.toString(word.getID())};
            update(Word.TABLE,contentValues,selection,args);
        }
    }
}

The code listing above is where my custom ORM works. That can be removed any time when I apply an ORM to my app thank to dependency injection. I just write a new class with support of ORM framework and use it instead (by binding to new class in IOCModule).

We traveled through many layers in app. Maybe you’ll ask yourself where is my SQLiteOpenHelper where I create database, upgrade and build up the connection? Well it is buried at deepest layer, you have to dig deeper. My SQLiteOpenHelper is called DbContext (like EntityFramework 🙂 ) hides under BaseDAO class.

public class BaseDAO {
    protected DbContext db;

    public Cursor loadAll(String table,String[] columns) {
        return db.getReadableDatabase().query(table,columns,null,null,null,null,null);
    }

    public void setContext(Context context) {
        db = new DbContext(context);
    }

    public Cursor loadAll(String table, String[] columns, String selection, String[] args) {
        return db.getReadableDatabase().query(table,columns,selection,args,null,null,null);
    }

    public void insert(String table,ContentValues contentValues)
    {
       db.getWritableDatabase().insert(table,null,contentValues);
    }

    public void update(String table, ContentValues contentValues,String selection, String[] args) {
        db.getWritableDatabase().update(table,contentValues,selection,args);
    }
}

public class DbContext extends SQLiteOpenHelper {

    public static final String DATABASE_NAME = "Dictionary.db";
    public static final int DATABASE_VERSION = 1;

    public DbContext(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        //To change body of implemented methods use File | Settings | File Templates.
        db.execSQL(new Migration_0001().getSQLQuery());
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        //To change body of implemented methods use File | Settings | File Templates.
        switch (newVersion)
        {

        }
    }
}

So now you reach the deepest layer. But is it really deepest? It seems not to be, it still call other function from migration classes. Yes, you’re right but it’s already deepest layer, the migration classes are only helper classes where I store migration SQL queries. So far so good, I hope that after this post, you’ll find out how to apply dependency injection and use beautiful MVVM pattern for your app. The source code of example you can download at “De-De-Dict“.

2 thoughts on “Android, Dependency Injection (IOC) with roboguice and MVVM (Model-View-ViewModel) pattern”

  1. Great post! I was just choosing between Roboguice and AndroidAnnotations, but your examples looks absolutely perfect, so I will start off with Roboguice and see how that works out. Thanks!

Leave a Reply

Your email address will not be published. Required fields are marked *