June 28, 2015

Painless Android development with Groovy and SwissKnife (part 1 of 3)

After Groovy recently introduced support for Android, I wanted to give that platform another try. In this blog post, I will guide you through setting up a development environment for Android based on ease of development and show you how modern frameworks may help us create more maintainable Android apps in the future.

As an experienced Java EE and Groovy developer, I was genuinely shocked when I first came in contact with Android software development. In my opinion, it simply ignores some major progress towards ease of development and maintainability as the Java EE stack achieved it and as it is implemented by Groovy. Most prominently, I see these major inconveniences:
  • No MVC pattern. Development with Android feels like development with Swing, with validation, even handling and business logic cluttered all over the place, and with view components hard-wired into the controller code.
  • No O/RM out-of-the-box. Working with the DB on Android is a step backwards to hard-coded SQL querying.
  • XML hell. Whilst Java EE makes great effort to minimize XML configuration by preferring annotations, Android uses XML for about every non-Java artifact, including message bundles.
Or, as Guillaume Laforge (former Groovy project lead) puts it, “Android is in the Java stone age”. Luckily however, tools and frameworks are emerging with the aim to make Android software development not only more productive, but also more enjoyable. Most prominently, with Version 2.4, Groovy included official support for Android’s Dalvik JVM and as such gave birth to a growing ecosystem of Groovy Android libraries upon which the SwissKnife project is the most prominent one.

With this tutorial, I want to push support for modern development practices, productive frameworks and useful tools for Android development to their current limits. What I want to achieve is:
  • Minimize any kind of boilerplate code
  • Two-way databinding to strengthen model / view decoupling
  • Getting rid of XML resource files in favor of more maintainable file formats, such as properties files.
  • ORM to allow declarative, object-oriented persistence querying
Due to the limited amount of time I’m ready to invest in this topic, I will concentrate on presenting some basic implementations and sketching ideas on how development experience could be further increased. Nevertheless, this tutorial will include a fully-functional implementation of the aims stated above.

The example application

As an example application, I will implement a very simple, fun memorization tool.

The user can create, edit and delete cards which consist of two texts.

He can start a game with all created cards. The application will then randomly choose a card and show one of the two texts that card contains; the user has to correctly enter the second text. If he guesses it right, the number of right guesses of that card is increased. That way, the user can later inspect which cards he guessed right a couple of times and delete them as he has successfully memorized them.

This is how the final application will look like. It will consist of four activities:

MainActivity: This is the starting point for playing a game or editing cards. CardActivity: This is the in-game screen. It shows one card at the time. After the user clicks OK, the current guess is evaluated and the next card is shown. If the guess was wrong, an error message appears briefly; otherwise, the card’s correct guesses number is increased and stored immediately.
CardSetActivity: Here, the user can enter the default description for the two text fields of a card. He can inspect all available cards, delete cards (with immediate effect), and change to the card edit screen to edit an existing or create a new card. CardEditActivity: Here, the user can inspect an existing card and change its two texts, or create a new card. A click on save saves the card immediately and leads back to the card set overview.

Note: The application is purposefully kept very simple. There is no support for multiple card sets, no error handling and the GUI is arguably ugly. I have neglected those aspects in order to concentrate on simple functionality showcasing the usage of tools and libraries.

Basic Setup

Android Studio

I will use Android Studio here which is Android’s official development platform. It is based on IntelliJ IDEA.

You typically want to use a real hardware device to test your application, mostly for performance reasons. Make sure that Android Studio is properly set up, follow the Android development documentation to setup the USB driver.

For convenience, follow this tutorial to add a “Groovy class” option to the “new file” dialog. The template may e.g. look like this:
#if (${PACKAGE_NAME} && $PACKAGE_NAME != "" )package ${PACKAGE_NAME}

import groovy.transform.CompileStatic

class ${NAME} {

Setup Android Project

I created a new Android project targeting the 4.1 SDK, starting with a blank activity named MainActivity. According to IntelliJ / Android Studio project structuring, I stick to the “one module per project rule” for Android projects.

Groovy on Android


Follow the official Groovy Android Gradle plugin documentation to activate Groovy in your Android project.

You may as well reuse my project build.gradle file and my module build.gradle file.

According to the Groovy-Android documentation, Groovy sources must be placed in project/app/src/main/groovy folder rather than in .../java folder. You have to change to “project” view to create the folder and for it to stay visible. Moreover, Java classes which refer to Groovy classes must be placed in the .../groovy folder as well. Thus just put all source files (Java and Groovy) in the .../groovy folder to avoid trouble.

The Android build system ships with the ProGuard code minification tool which we will use to purge any non-used Groovy library files from the classpath in order to keep the release APK footprint small.

I used the example proguard-rules.pro file of this GitHub repository as a base for my project. My own proguard-rules.pro file contains some additional fixes. It minimizes a 9.20 MB APK down to 3.77 MB for a hello world application and a 9.38 MB APK down to 4.06 MB for the finished demo application. Enabling code obfuscation further minimizes APK size drastically, so don’t include the -dontobfuscate option, even though it is shown on several online resources.

To see minification in action during development, I enabled it for the debug buildType as well. I highly recommend you to do so as wrong proguard-rules will lead to exceptions at runtime, not compile time due to Groovy’s use of reflection.

In action

With this basic setup done, you’re ready to write Groovy code for your Android application. In and of itself, this is potentially a huge productivity gain already as you can now use Groovy’s very concise syntax as well as its comprehensive API.

However, you should always keep your Groovy classes @CompileStatic for performance reasons as well as for type safety and to support code minification – otherwise, reflection is used which doesn’t provide any of these goodies. Remember to do so as well if you change an Android Studio-generated Java file (e.g. an Activity class) to *.groovy.


The combination of Proguard code minification and Groovy is tricky especially if you are forced to omit @CompileStatic / use @CompileDynamic for your classes as these are then eligible for deletion during minification process. To prevent this, you can exclude every class in your project’s base package in the proguard-rules:
-keep class ch.codebulb.groovyswissknifeandroidapp.**
-keepclassmembers class ch.codebulb.groovyswissknifeandroidapp.** {*;}
You should do that anyway. After all, if you really had code in you packages which you don’t need, you would just delete it, wouldn’t you?

Otherwise, you will get strange errors at runtime when your application tries to invoke code which isn’t there:
AndroidRuntime? FATAL EXCEPTION: main
    java.lang.RuntimeException: Unable to start activity ComponentInfo
    groovy.lang.MissingMethodException: No signature of method: 
    groovyjarjaropenbeans.PropertyChangeSupport.firePropertyChange() is applicable for argument types: 
    (java.lang.String, groovy.util.ObservableList, groovy.util.ObservableList) values: 
    [cards, [], [ch.codebulb.groovyswissknifeandroidapp.model.Card@41927e20, ...]]
    Possible solutions: firePropertyChange(groovyjarjaropenbeans.PropertyChangeEvent)
            at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2092)
     Caused by: groovy.lang.MissingMethodException: No signature of method: 
    groovyjarjaropenbeans.PropertyChangeSupport.firePropertyChange() is applicable for argument types: 
    (java.lang.String, groovy.util.ObservableList, groovy.util.ObservableList) values: 
    [cards, [], [ch.codebulb.groovyswissknifeandroidapp.model.Card@41927e20, ...]]
    Possible solutions: firePropertyChange(groovyjarjaropenbeans.PropertyChangeEvent)
            at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.unwrap(ScriptBytecodeAdapter.java:56)
Also there seems to be a problem with enums. If you declare an enum yourself, you may end up with an exception like this:
AndroidRuntime? FATAL EXCEPTION: main
            at ch.codebulb.groovyswissknifeandroidapp.observer.ViewAttribute.text(Unknown Source)
            at ch.codebulb.groovyswissknifeandroidapp.CardActivity.initListener(Unknown Source)
     Caused by: java.lang.IllegalArgumentException: 
    This class has been compiled with a super class which is binary incompatible with 
    the current super class found on classpath. 
    You should recompile this class with the new version.
            at ch.codebulb.groovyswissknifeandroidapp.observer.ViewAttribute$Type.$INIT(Unknown Source)
            at ch.codebulb.groovyswissknifeandroidapp.observer.ViewAttribute$Type.(Unknown Source)
            at ch.codebulb.groovyswissknifeandroidapp.observer.ViewAttribute.text(Unknown Source)
            at ch.codebulb.groovyswissknifeandroidapp.CardActivity.initListener(Unknown Source)
I ended up just not using any enums myself. I should probably examine this a little bit closer at some point…

Also Proguard sometimes has a problem with closure methods, especially on collections:
AndroidRuntime? FATAL EXCEPTION: main
    b.b.cg: No signature of method: java.util.ArrayList.each() is applicable for argument types: 
    (ch.codebulb.groovyswissknifeandroidapp.observer.TextViewBinding$1$_afterTextChanged_closure1) values: 
    Possible solutions: wait(), head(), max(), any(), last(), head()
            at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.a(Unknown Source)
            at org.codehaus.groovy.runtime.callsite.PojoMetaClassSite.a(Unknown Source)
            at org.codehaus.groovy.runtime.callsite.CallSiteArray.a(Unknown Source)
            at org.codehaus.groovy.runtime.callsite.AbstractCallSite.a(Unknown Source)
            at org.codehaus.groovy.runtime.callsite.AbstractCallSite.a(Unknown Source)
            at ch.codebulb.groovyswissknifeandroidapp.observer.TextViewBinding$1.afterTextChanged(Unknown Source)
            at android.widget.TextView.sendAfterTextChanged(TextView.java:7417)
In this case, I replaced the closure call with an equivalent for loop.

Pages: 1 2 3