The Why and How of Clojure on Android

By Zach Oakes on April 3rd, 2013

I love crazy, impractical ideas, and Nightweb has its fair share. The one I want to focus on in this piece is writing Android apps in Clojure. To me, this is a marriage of my favorite operating system with my favorite programming language. Apart from any pragmatic justification, I want to do this because it is cool, and that reason alone would suffice for me. Others may require more convincing, though.

I'm indebted to two people in particular: Daniel Solano Gomez for porting Clojure to Android and writing useful wrapper functions in the neko library, and Alexander Yakushev for writing the excellent lein-droid plugin that dramatically simplifies the process by allowing leiningen to be used. One side benefit of this is that we can completely skip the standard Eclipse toolchain and use whatever tools we want.

While Clojure started its life mainly as a server-side language, the advent of ClojureScript demonstrates that the core developers don't see that as its only purpose. Rich Hickey has stated in the past that Clojure is suitable for everything Java is used for; since Java is used to write Android apps, one would assume Clojure could as well. It was already possible to use ClojureScript to write PhoneGap apps, but I'm far more interested in the full power of Clojure and the superior experience of native apps.

The most obvious benefit you'll find is brevity. Nightweb's codebase is less than 3,000 lines of Clojure at the moment, which is shockingly small compared to what the Java equivalent would have been. One of my favorite ways to demonstrate the difference is to compare how you would perform a resource-intensive operation in a separate thread and update the UI when it's done. This is a very common thing many programmers must do, and you'll find it in many places within Nightweb's codebase:

  (future
    (let [user (get-single-user-data {:userhash ptr-hash})
          path (get-pic-path (:userhash user) (:pichash user))
          bitmap (path-to-bitmap path thumb-size)]
    (on-ui (.setText user-name (:title user))
           (.setImageBitmap user-img bitmap))))

This code queries the database for a given user so we can get their username, then reads a picture from the disk and downscales it to a thumbnail. These are resource-intensive tasks, so we run them within a future so they are performed on a separate thread. Finally, we use neko's on-ui macro to return to the main thread and update the UI. The equivalent in Java would require using AsyncTask in which you override the doInBackground method, as Alex demonstrates half-way down in in this blog post. The difference is quite stark.

Imagine you are teaching this technique to a young programmer who wants to learn how to write apps for his phone -- which do you think he will pick up on faster? I think this demolishes the notion that functional languages are too obscure and difficult to teach as a first language. Not only is the Clojure code simpler, but it encourages the student to engage in great habits like limiting mutations and breaking code into composable functions instead of monolithic classes, which will benefit him no matter what language he learns later on.

I don't think it only benefits new programmers, though. Multi-core phones are now the norm, so threads aren't just important for UI responsiveness, but also raw performance. This is particularly true for complicated apps where separate threads must interact with shared state. In Java, this usually means manual mutex locking, which is dangerous and potentially inefficient because you'll often resort to locking a single global object for simplicity. With Clojure's high-level concurrency primitives, the locking behind the scenes could possibly be more efficient and undoubtedly far simpler for the programmer.

It isn't all good news, though. Clojure imposes a significant startup time for apps, so it is best to only use it for apps meant to run for long periods of time. I think that makes it a good fit for apps that run services (like Nightweb) and, intriguingly, games. It's better than it used to be, but there is still more that can be done. As I've said before, I think more people need to write Clojure apps for Android, and eventually it will be a strong signal to the core devs that it's a platform worth optimizing for.

Additionally, it must be noted that you won't be escaping the standard Android API docs any time soon. The neko library is great, but it's just for convenience and doesn't cover everything. It may even be necessary to copy out some of its functions in order to add functionality you require; for example, defactivity doesn't support every method in the Activity class, so I had to add them myself. Eventually, I imagine this or some other library will provide greater coverage of the Android API so development can be more "clojuresque".

To get started, please check out the lein-droid project and read its tutorial. There is also the clojure-android Google group. As a test, you could try building Nightweb, which is as much of as stress test as you can imagine (over 850 Java files!). Like most great ideas early in their life, Clojure on Android is immensely fun, frustratingly undocumented, and sometimes stupidly impractical, and that's why I love it.