I’m the author of CalWatch (Play Store link, Github link), an Android Wear watchface that renders your free/busy time around the twelve hours of the dial. It’s been my side project for a while and it’s all open source.
Anyway, with the move to Android 6’s new permission model, I had to make a bunch of changes to support the new world order, so I figured I might as well port my app from Java to Kotlin while I’m at it. This post documents my experiences, good and bad.
Getting started. I began with the Java → Kotlin converter that’s built into Android Studio / IntelliJ. I did this one file at a time, cleaning up each file in turn until there were no errors, then moving onward. This process took about a day and was mostly straightforward. The Kotlin IntelliJ plugin is still a bit sensitive, and it was crashing all over the place until I straightened out all of the bugs in my translated code. This required quitting and restarting Android Studio every time, so it was a bit painful, but once I got my port compiling without errors, the Kotlin plugin has been stable ever since.
Compiling != Working. Kotlin tries to come up with inferences about the nullity of all the callbacks from Android to your Activity. Well, it’s wrong in a bunch of places. I had to add a bunch of question marks. Also, the converter tries to figure out your getters and setters and turn them into properties. This can be confusing and was the source of several bugs for me.
vars and !!'s everywhere. My code had a bunch of places where it would check if some field was null, and if not, would then start using it. This translated to Kotlin var
fields, with every usage having !!'s before its dereference. It’s generally considered good Android style to null things out if the OS tells you you’re being shut down, so you can’t just use a lateinit
modifier on a val
. Ultimately I had to create a bunch of local val’s to copy the class var’s, so the not-null inferences would flow properly. This seems less than awesome.
One transformation that made me happy was replacing old-school list comprehensions like so:
if(stuffList != null) {
for(stuff in stuffList!!) {
...
}
}
With this:
stuffList?.forEach { ... }
Comments. As part of the automatic translation process, the Java → Kotlin converter tries to preserve your comments. They don’t always end up in the right place, so you have to rummage through all your code and move things, by hand, to make sure they make sense.
Hex numbers. For a bunch of color constants, my Java code had hexadecimal constants. The Java → Kotlin translator converted those to base ten. (Yuck!) Converting them back to hex, by hand, bumped me into a known bug in Kotlin. The issue is that you can’t represent a hex number whose high bit is one, because, as a signed int, that would be a negative number. The workaround is appending .toInt()
to your hex number in these cases.
Mixed integer / floating point expressions. I have some fun logic that tries to make my second-hand sweep in a non-linear way, like some European rail clocks. I had it working just fine in Java, but the Kotlin translator didn’t produce an equivalent expression, resulting in incorrect results. The fix was no big deal, but if you’ve got such expressions in your Java code, pay careful attention to the output of the Kotlin translator.
Making sure Android can find your classes. Android has this AndroidManifest.xml
file, which specifies a bunch of entry points for your Activity
and other such things. I had to add explicit @file:jvmName
annotations to the relevant Kotlin classes to make everything work. EDIT: Apparently I was wrong about this and the annotation isn’t necessary. Anyway, if you get weird logcat errors about it not being able to find your classes, pay attention to this.
Taking advantage of Kotlin features. Once I finally had things working, I started leveraging the cool features of Kotlin. The kotlinx.android.synthetic
feature makes it much easier to hook into your UI widgets. That was easy. I also had some code that was perfect to rewrite using Kotlin’s functional list mapping, filtering, and sorting. That make things much more clean and concise. Similarly, I was able to leverage Kotlin data classes in a few places, again simplifying my code from the original translation.
Functional-reactive. I made a brief stab at this, since the part where I fetch calendar data from the system calendar provider is a complicated mess of AsyncTask
, BroadcastReceiver
, and Handler
which would seem to be crying out for an application of reactive programming. The relevant “Rx” libraries seem to be in a state of flux, so I decided to put this off for later.
All said and done. My previous APK, based entirely on the Java code, and after compression via ProGuard, was about 1.5MB. My new APK, with new features, including a new icon for saying “hey, I can’t see your calendar” and with whatever extra Kotlin libraries included, is about 1.4MB. That’s not a typo. The translation to Kotlin somehow made my final APK smaller than it originally was, despite all the new features I added. At this stage, I’m still testing it out on myself to make sure I’ve got it all working, and Google hasn’t started pushing Android 6 to wear devices yet, so I’m not going to push the APK to the public. That said, if any of you want to be beta testers, do let me know.