Android Developers
Published in

Android Developers

Illustration by Virginia Poltrack

Re-writing the AOSP DeskClock app in Kotlin

Why Kotlin?

We chose to convert the AOSP DeskClock app in part due to Kotlin’s many benefits over Java, including the following:

  • Built-in null safety, which can substantially reduce null pointer exceptions in your app.
  • Conciseness, or writing less code to do more work.
  • Google’s “Kotlin-first” support for Android development means that new Android development tools and content such as Jetpack libraries and online training will be built with Kotlin users first in mind.

The Conversion Process

The DeskClock app is quite large, containing 160 Java files with a total of 31,914 lines of code before conversion began. Because of its size, the code had to be converted incrementally. In AOSP, this was done by creating a separate Soong build target (DeskClockKotlin), excluding any Java files with Kotlin equivalents. Kotlin’s interoperability with Java made this process straightforward by allowing the DeskClockKotlin target to continually include more Kotlin files as the corresponding Java files were converted.

Manual Work To Be Done

During the conversion process, we ran into some issues that required more manual work after running the auto-conversion tool. This section discusses a few of the more complex issues in depth, followed by short summaries of additional minor issues.

Unable to Run Auto-Conversion on Some Files

One of the most time-consuming issues we encountered was the inability to run the Kotlin plugin’s auto-conversion tool on certain Java files. This was not a common issue, occurring only twice in the first ~75 files converted. However, we did need to either rewrite the Java code completely in Kotlin or spend time investigating the issue.

try (Cursor cursor = db.query(…)) {
// some code in here
}
val cursor = db.query(…)
cursor.use {
// some code in here
}
private String safeGetString(@StringRes int resId) {
return resId == 0 ? null : mContext.getString(resId);
}
private fun safeGetString(@StringRes resId: Int): String? {
return if (resId == 0) null else context.getString(resId)
}

Static Constant Inheritance

An additional complex issue we encountered was the difference in inheritance abilities between Java and Kotlin. This issue occurred in the ClockContract.java file, where static constant values are defined within interfaces that inherit from each other. This is not a problem in itself. However, many places in the codebase attempted to reference the constants through children of these interfaces, which is not possible in Kotlin.

Manual Nullability Fixes

One other common issue that came up during the conversion process was the occasional inaccuracy of nullable types in the converted Kotlin code. For example, converted code incorrectly specified that a function accepts a String instead of a String? parameter, which could result in runtime errors. These issues can be avoided if the converter tool is able to deduce from the Java code whether or not a parameter or return type is able to be null. You can annotate Java code with @Nullable and @NonNull to give the IDE the information needed to make this decision correctly. Otherwise, it’s possible to manually fix these nullability issues in the resulting Kotlin by tracing through the code and determining whether it is possible to receive or return a null value.

Additional Issues

In addition to these more complex issues, we encountered multiple smaller issues during the conversion process. Each issue had a quick fix that didn’t take much time to address.

Quick Conversion Tips

The following list aims to quickly summarize the more detailed explanations of the issues encountered above into actionable items to help speed up the conversion process:

  • Ensure usages of “===” and “!==” are used for checking referential equality
  • Remove any @NonNull or @Nullable annotations in the Kotlin code
  • Check that single line comments are located in their desired places and not duplicated
  • Add back removed blank lines within functions to match the style of the Java code
  • Fix any incorrect casting attempts between number values
  • Improve code readability by renaming local variables that shadow names of function parameters
  • Remove unnecessary private keywords on get() accessors on private properties

Outcomes

Right now, approximately half of the DeskClock app’s Java files have been converted to Kotlin. We’ve replaced 15,886 lines of Java code with an equivalent 15,240 lines of Kotlin code. The conversion of these Java files took roughly one month of engineering to complete. Through this Kotlin conversion process, as well as this article, the AOSP DeskClock app is better able to fulfill its goal of being an example for Android development best practices.

Next Steps

To learn more about the Java to Kotlin conversion process for Android, check out the Get Started with Kotlin on Android documentation or the Kotlin for Java Developers Pathway. If you’d like to look at the codebase, you can check out the AOSP source code by following the Downloading the Source documentation.

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store