Migrating an Android App from Java to Kotlin

Philipp Hofmann
Monster Culture
Published in
7 min readNov 3, 2017
mySugr office in Vienna

One year ago when developing Android, you were limited to Java 6 with some features of Java 7. If you are used to Java 8, C#, Groovy, or Swift, you feel limited with Java 6. There is no type inference, lambdas, properties, extension methods, non-nullability, etc. Some developers were using Retrolambda to ease the pain, which allows you to use Java 8 code with lambda expressions and method references on Java 7, 6 or 5. Others used Lombok to get rid of the boilerplate generated getters and setters.

Even still, using Java 7 with Retrolambda and Lombok was not satisfying for us at mySugr. That’s why Kotlin caught our attention. It was still a quite new language one year ago and we didn’t have any experience with it. Having cool features like C#, Groovy, and Swift do, and compiling to Java 6 bytecode, which means you can run it on Android, convinced us to take a closer look at Kotlin. Our biggest concern in the beginning was that Google did not officially support Kotlin on Android, even though the popularity of Kotlin was already growing. For example, Jake Wharton gave a talk in December 2015, that we Android developers are stuck with Java 6 and we needed a revolution like Kotlin. So we wanted to be a part of this revolution and push Kotlin, so that hopefully Google will officially support it soon. We also still had a few major concerns:

  • Is it interoperable with Java?
  • How hard is it to move Java to Kotlin code?
  • Does it affect the performance and how big is the overhead?
  • Will it cause any problems? If yes, how big are they?

Let’s try Kotlin

Our entire codebase was in Java, therefore we had the concern if Kotlin could play nicely alongside with Java. We started with configuring Kotlin for our app and wrote our first classes. The plan was that a new code is written in Kotlin and we steadily convert those classes from Java as we touch them. Soon we found out that both work fine together: you can call Java code from Kotlin and vice versa. Actually, the interoperability with Java is one of the core features of Kotlin.

The Kotlin plugin for the Android Studio has a feature for converting Java to Kotlin classes. You can find it under Code > Convert Java File to Kotlin File. Also, when you paste Java code snippets to a Kotlin file, the plugin prompts you if you want to want to convert the pasted code to Kotlin. There were a few minor problems with nullability, not using lateinit, or overusing companion objects occur most of the time which then force you to make smaller changes to the converted code, but we never had major problems. On the whole, the conversion works fine.

Kotlin build process, from Kotlin in Action

What about the overhead and the performance? Since Java compiler doesn’t optimise the byte code during compilation, but leaves it to the java runtime, Kotlin compiler wasn’t something that worried us. What did worry us, however, is how Kotlin implements some features that are not available in Java 6, like lambdas. For lambdas, unless they are inlined, the Kotlin compiler generates an object on the heap for each lambda. If you were using Java, you would have to create an anonymous class. So there is not a big difference. The standard library and the runtime jar files are less than 1 megabyte and they contain around 6500 methods. So the overhead of Kotlin is small, especially compared to Android support libraries. According to the Android documentation, Kotlin should not affect the performance of the app. Although, in a blog post , Renato Athaydes benchmarks some hidden costs of Kotlin, just as Christophe B. also described it in a blog post series. Almost all of the features from Kotlin have a performance cost below 5%. Calling forEach on Ranges, for example, has a cost around 300% and should be avoided. So, overall this is not a show breaker for us. If you notice performance breakdowns, which we didn’t, it’s good to know those issues. Furthermore, you can always go back to write performance critical code in Java.

Problems with Kotlin

A lot of current blog posts demonstrate how fancy Kotlin is, but we also had some problems with it.

Annotation Processing

Enable Kotlin kapt in the gradle file

The biggest problem is that the Kotlin Annotation Processing Tool (KAPT) is still somewhat buggy. APT is needed for some of the most popular Android libraries, like Dagger, Retrofit, and Realm.

Last year, we wrote a small part of our app that calculates how much insulin a user should inject as a standalone module completely in Kotlin. When we integrated the module into the mySugr app, we had strange build errors. We could trace them back to Dagger and Kotlin APT. So we had two different options: Either use Java and Dagger, or Kotlin without Dagger. We liked Kotlin way more than Dagger. Therefore, we dropped Dagger and created our own dependency injection. We are going to show you this in another blog post.

We still have problems with Dagger in the mySugr app. Our current workaround is to write our modules and components for Dagger in Java, which is not a huge drawback for us. What is a little bit annoying is that we have to write our Realm entities in Java. But again, if we were using Java, we would have to write them in Java anyway.

What is working fine with Kotlin is Retrofit. Our entire code with Retrofit is written in Kotlin.

Mockito

Mockito often returns null when using methods like any(), eq()or argThat(). Because Kotlin has null safety, it throws a NullPointerException when null from Mockito is passed to non-nullable parameters. Another library, Mockito-Kotlin, is supposed to solve this problem. Having problems with Mockito-Kotlin and not wanting to be dependent on another library, we found a simpler solution. We just use the Elvis Operator. For example, we have a class LoginService with a method login. We want to mock the login method in a unit tests and use argThat(). The only thing we need to do is to append ?: “” after argThat()and it is working.

Elvis operator with Mockito to avoid NullPointerException

There is also an issue with mocking Kotlin classes, which are final by default. Before, Mockito v2 a class needed to be open, so proxy classes can be generated for it. If you can’t use Mockito v2 this forces to declare your classes as open or to implement interface behind each class you intend to mock.

Kotlin Compiler

Until now, we only had one problem with Kotlin compiler. We experienced a strange bug with the Elvis operator, which caused a method to exit early if variable is null. When trying to reproduce it with similar code, outside of our code base, everything worked fine. Also, inspecting Kotlin generated bytecode showed nothing wrong. So, we are still not sure what was happening.

Android Studio Plugin

Kotlin Plugin

Jetbrains provides Kotlin language support with a plugin for Android Studio. For each new version they release, they also publish a new version of the plugin. We experienced issues several times when the version of the runtime and the plugin didn’t match. When this happened, suddenly, the annotation processing was not working anymore. We also had strange issues with android data binding or other random compile errors. So, now, we try always to keep both runtime version and plugin version in sync. Since doing that, we don’t have any problems.

Conclusion

After over one year experience with Kotlin, we have to admit we had several problems. Some very easy to fix, others little bit harder. All in all, we could resolve the issues and it caused less problems than we expected. Android developers at mySugr love Kotlin and can’t imagine to live without it. We love it so much that we already started to use it also on the backend, where we use currently Java 8, and the pain is not so huge as with Java 6. When we have more experience, we are going to write about this in another blog post.

In the end, we are proud to be one of the early adopters of Kotlin, and were very happy when Google announced the official support for it on May 17th, 2017 during Google I/O.

Thanks to Marko Devcic for the initial ideas and parts of this blog post.

mySugr specializes in app-based, all-around care for people with diabetes — made by people with diabetes. Our apps, services, and access to the world’s best diabetes coaching at the tap of a finger all work together to ease the daily grind of diabetes. In short, we make diabetes suck less!

Interested in joining our engineering team? We’re hiring!

--

--