Time is due for my usual report about the state of Clojure Android combo. During this time lein-droid was touched only lightly as I rewrote the version resolving part of the plugin (one that chose the latest version of the library on classpath if more than one were provided) to use aether library.
But most changes were done to neko of course. A brief rundown on new things follows.
ListView is a very big topic that has to be dealt with eventually so I started with some utility functions for multi-check ListViews first.
By default calling .getCheckedItemPositions on a ListView object returns a SparseBooleanArray instance that is not exceptionally delightful to work with. That is why I wrote get-checked which when given a ListView returns a list of integers that represent the IDs of elements being checked. If provided a second argument (a list of all values in the ListView) returns a vector of only those elements that are checked. Screenshot on the right shows this in action.
set-checked! obviously checks elements whose numbers are respective to the integers in the given list.
Adapters are currently constructed via interop but they need some kind of wrapper too, especially for defining custom views for elements (it would be nice if defui could be harnessed for that as well).
Mobile application should be responsive at all costs. That means staying responsive no matter what complex computations or large amount of IO you are performing at any given moment. Since Android runs on Java-like Virtual Machine it is essential to use multithreading to separate the UI code execution from some time-consuming activities.
Android SDK has this thing called AsyncTask to deal with (wait for it) asynchronous tasks. It is an abstract class that you should extend in your code and provide the following methods: onPreExecute, onPostExecute, onProgressUpdate and doInBackground. First three methods are executed on the UI thread, the last one - on the individual thread. This allows a task to be run asynchronously but at the same time communicate with UI about its progress.
For you to have a general impression how it is done in Java here's the code:
So in order to deal with this pile of terrifically incidental complexity I wrote... nothing! Clojure's native capabilities and on-ui macro I wrote so far was enough to implement asynchronous tasks simply and idiomatically. The same code in Clojure:
Besides being three times shorter the implementation in Clojure has one more important advantage - the whole task is in the same lexical scope, so you don't need tricky callbacks to pass the data around it - everything is available everywhere.
But most changes were done to neko of course. A brief rundown on new things follows.
New features in defui
After I introduced eval inside defui macro I missed one not-so-subtle bug. The macro worked as following: if the UI element is a vector - then it is considered an UI tree form and processed respectively, otherwise it is considered a language element to evaluate and pass through defui one more time. So if you add a form that doesn't eventually return a vector, the compilation will end up in the infinite loop.
Now you can add arbitrary objects created in runtime by quoting their symbol/form. For example, this code will create a LinearLayout and add a button to it:
One more useful feature is a new :def attribute for elements. Previously I used :id attribute, which registered an element in the global map and allowed further fetching by executing something like (by-id ::ok-button). Now you can directly provide a symbol to :def, which the element would automatically be bound to. See an example (dots mean there could be other code there):
This approach is more convenient (don't have to call anything to get the object) and faster (no time is wasted to fetch the object from the map).
Now you can add arbitrary objects created in runtime by quoting their symbol/form. For example, this code will create a LinearLayout and add a button to it:
(let [but (Button. context)]
(defui [:linear-layout {:orientation :vertical}
'but]))
One more useful feature is a new :def attribute for elements. Previously I used :id attribute, which registered an element in the global map and allowed further fetching by executing something like (by-id ::ok-button). Now you can directly provide a symbol to :def, which the element would automatically be bound to. See an example (dots mean there could be other code there):
(defui ... [:text-edit {:def price-edit ...}])
...
(.getText price-edit)
This approach is more convenient (don't have to call anything to get the object) and faster (no time is wasted to fetch the object from the map).
First primitives for ListView
![]() |
| Two-argument version of get-checked |
By default calling .getCheckedItemPositions on a ListView object returns a SparseBooleanArray instance that is not exceptionally delightful to work with. That is why I wrote get-checked which when given a ListView returns a list of integers that represent the IDs of elements being checked. If provided a second argument (a list of all values in the ListView) returns a vector of only those elements that are checked. Screenshot on the right shows this in action.
set-checked! obviously checks elements whose numbers are respective to the integers in the given list.
Adapters are currently constructed via interop but they need some kind of wrapper too, especially for defining custom views for elements (it would be nice if defui could be harnessed for that as well).
Intents and Bundles as maps
This one was fun to implement. Since Bundles (things that can store activity state or send some data to another activity) are basically maps but don't directly subclass ones I wrote a wrapper called like-map that allows to treat them as Clojure maps.
Here is how it looks:
The whole power of destructuring is available to you instead of boring calls to .getInteger, .getBoolean and the like!
Here is how it looks:
(defactivity ...
:on-create
(fn [this bundle]
(let [{:keys [sharks-num with-lasers?]} (like-map bundle)]
...
The whole power of destructuring is available to you instead of boring calls to .getInteger, .getBoolean and the like!
SharedPreferences as universal data storage
If Bundles are used to store some short-lived data while the application is running, SharedPreferences are for storing data between application restarts. like-map supports SharedPreferences as well but there is one more thing to it interesting on its own.
Initially SharedPreferences class supports saving a very limited number of primitive types - integers, booleans, floats and strings. Even for a small array of primitive type you need to use some other local storage (SQLite for instance). But having Clojure reader facilities at hand its a little hard to bear with...
So I didn't: assoc-arbitrary! when called on SharedPreferences.Editor object saves an arbitrary Clojure data structure into SP by serializing it into a string. Then you can read this data by calling get-arbitrary on the like-mapped SP object.
You can still use primitive values with assoc! to avoid serializing primitives.
Keep in mind that Clojure reader is a relatively slow serialization mechanism. If you have a large amount of data to save, then DB or file should be preferred.
Initially SharedPreferences class supports saving a very limited number of primitive types - integers, booleans, floats and strings. Even for a small array of primitive type you need to use some other local storage (SQLite for instance). But having Clojure reader facilities at hand its a little hard to bear with...
So I didn't: assoc-arbitrary! when called on SharedPreferences.Editor object saves an arbitrary Clojure data structure into SP by serializing it into a string. Then you can read this data by calling get-arbitrary on the like-mapped SP object.
(-> (.edit shared-prefs)
(assoc! :cpu-level 3)
(assoc-arbitrary! :game-info {:sharks-num 3,
:shark-health [100 30 75]})
.commit)
You can still use primitive values with assoc! to avoid serializing primitives.
Keep in mind that Clojure reader is a relatively slow serialization mechanism. If you have a large amount of data to save, then DB or file should be preferred.
Doing things asynchronously
![]() |
| It's 25% and rising. |
Mobile application should be responsive at all costs. That means staying responsive no matter what complex computations or large amount of IO you are performing at any given moment. Since Android runs on Java-like Virtual Machine it is essential to use multithreading to separate the UI code execution from some time-consuming activities.
Android SDK has this thing called AsyncTask to deal with (wait for it) asynchronous tasks. It is an abstract class that you should extend in your code and provide the following methods: onPreExecute, onPostExecute, onProgressUpdate and doInBackground. First three methods are executed on the UI thread, the last one - on the individual thread. This allows a task to be run asynchronously but at the same time communicate with UI about its progress.
For you to have a general impression how it is done in Java here's the code:
final ProgressDialog pb = new ProgressDialog(this);
pb.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
pb.setText("Java is not a verbose language");
new AsyncTask<Void, Integer, String>() {
@Override
protected void onPreExecute() {
pb.show();
}
@Override
protected String doInBackground(Void... params) {
for (int i = 0; i < 100; i++) {
Thread.sleep(100);
publishProgress(i);
}
return "sample string";
};
@Override
protected void onProgressUpdate(Integer... values) {
pb.setProgress(values[0]);
}
@Override
protected void onPostExecute(String msg) {
pb.hide();
some_callback(msg);
}
}.execute();
So in order to deal with this pile of terrifically incidental complexity I wrote... nothing! Clojure's native capabilities and on-ui macro I wrote so far was enough to implement asynchronous tasks simply and idiomatically. The same code in Clojure:
(let [pb (defui [:progress-dialog
{:progress-style :horizontal
:text "Clojure conquering the world..."}])]
(.show pb)
(future
(dotimes [i 100]
(Thread/sleep 100)
(on-ui (.setProgress pb i)))
(on-ui (.hide pb)
(some-callback "sample string"))))
Besides being three times shorter the implementation in Clojure has one more important advantage - the whole task is in the same lexical scope, so you don't need tricky callbacks to pass the data around it - everything is available everywhere.
Dealing with resources
The initial neko by Daniel Solano Gómez already had a convenient way to resolve resources, so instead of writing your.package.name.R$id/foo you could do (get-id :foo). The problem with this approach lies in its poor performance - the time was spent to resolve a proper internal class and get a field from it using reflection.
And that got me thinking - why do it in runtime if..? You know the rest of the story. Resource-resolving utilities are now macros that simply return the field reference. It looks the same but has no performance overhead at all! Did I tell you why I love Lisp?
And that got me thinking - why do it in runtime if..? You know the rest of the story. Resource-resolving utilities are now macros that simply return the field reference. It looks the same but has no performance overhead at all! Did I tell you why I love Lisp?
Documentation
I wrote quite a description of nealy every neko namespace. It's not finished yet, but I'll append information on the rest namespaces soon. The docs are available here.
Summary
These two weeks involved deep thinking and some difficult decisions so the list of changes might not be that impressive. There is still a lot of stuff to do like ListViews and properly implement listeners for UI elements in defui. I hope to catch up with this in the following week. For now, thank you for your attention.










