One topic that’s been gaining popularity over the past year in the world of Android development is the Kotlin® language for the JVM from JetBrains. JetBrains is the same crew who created IntelliJ Idea, which is the foundation for Android Studio. Kotlin takes aim at the age and perceived uncoolness of the Java® language with fresh and popular language features. I imagine that the crew at JetBrains imagines it could potentially become a replacement for Java® programming for all kinds of development on the JVM. Because it’s 100% inter-operable with the Java language, you can choose to use as much or as little Kotlin in your project as you like. And because it has a relatively small standard library, it’s suitable for development on mobile devices with limited resources.
Kotlin can do anything the Java language can do and more, but often with a more concise and pleasant syntax. There is full IDE support in IntelliJ and Android Studio. Because I’ve been deeply involved with Android since 2009, my specific interest in Kotlin is to discover what it uniquely offers to Android developers. So I’m cutting through the hype in this blog series and getting down and dirty with Kotlin’s best language features, to see if I can make something truly useful.
Configuring an Android Project with Kotlin
The official docs on getting started with Kotlin will show you how to install the Kotlin IDE plugin, and use that to modify an Android project’s Gradle config to add support for compiling Kotlin source. I don’t recommend this particular process, because I found the result of the automation to be less than satisfactory. While the changes it makes to the project’s Gradle build files might technically work, they don’t seem to be consistent with the way that new Android projects are typically set up.
To be frank, I have never been a fan of any Android Studio plugin that tries to guess changes to make to Android builds — more often than not, they botch things up, and I have to redo everything it did to clean it up to my liking. Gradle build files are actually source code, and automated processes are not really good at making changes to existing code! So, if you’re picky like me, take the extra minute to configure your project manually.
If you want to follow along, we’ll take four quick steps to get up and running:
Create a new Android project.
Modify the Gradle scripts to include the Kotlin Gradle plugin and standard library.
Apply the Kotlin plugin for IntelliJ or Studio.
Convert a Java class to Kotlin.
First, create a new Android project using a template that adds an activity. When you have that, there are just five important lines of code to add across two build.gradle files, which I will highlight below. Let’s modify the top level build.gradle buildscript stanza with a couple of new lines:
This adds the Kotlin Gradle plugin into the build. Note the definition of the Kotlin version string defined in ext.kotlin_version. We’ll use it twice: once here in the buildscript classpath, and once in the app compile dependencies, and it must be the same in both places. You should of course use the latest version published via Maven. You can find the latest version documentedhere.
Next, apply the kotlin-android plugin after the Android plugin in the app’s own build.gradle after the standard Android plugin. This makes the project Kotlin-aware and adds a Kotlin compile step to the build, so that all the classes generated by both the Java and Kotlin languages get bundled together in the final app:
By convention, Kotlin files want to live under src/main/kotlin, but they could also live alongside Java files in src/main/java. So, let’s be conventional and tell Gradle to recognize a new source directory for Kotlin source within the Android project definition:
But how big is this library we’re adding? This is a great question. Every Android developer should be asking this question every time a new compile dependency is added. However, we’ll save that discussion for a later post in the series.
At this point, you should be able to do a command line Gradle build as you would normally with gradlew, and you can also build and deploy an APK from Android Studio. Nothing should change except the size of the app, which grows with the Kotlin standard library.
So that’s the Kotlin Gradle plugin, and adding it to your project like this is sufficient to build and run Kotlin code in the project. But you’ll probably also want IDE support for Kotlin language features. If you haven’t already installed the Kotlin plugin for IntelliJ or Android Studio, now is a good time for that.
Installing the IDE plugin is just like any other. You can find that under Preferences → Plugins → Install JetBrains plugin. Be sure to restart the IDE after installation. With that, you’re done with setup. I’ve found that the IDE support for Kotlin is almost as good as for the Java language, but I would expect as much, since JetBrains makes both the IDE and Kotlin!
From Java to Kotlin the Easy Way
One interesting feature of the IDE plugin is its action for converting Java source to Kotlin source. The plugin is smart enough to replace Java idioms with Kotlin idioms while retaining full runtime compatibility. If you’ve created a new Android project to try this out, go find the main activity that was generated for you, select it in the project explorer on the left, and invoke the IDE action called “Convert Java File to Kotlin File”. You can do that by bringing up the action selector with Command-Shift-A (on OSX), then typing that action name. The plugin also provides a finger-bending keyboard shortcut for this action (on OSX it’s Option-Shift-Command-K). So, enjoy typing that! Note that the official documentation for this conversioncurrently does not suggest 100% correct behavior for this action, but I haven’t encountered a problem so far.
If you convert a Java file like this, you’ll end up with a Kotlin .kt file in place of the original .java file like this:
Notice that MainActivity has a Kotlin K logo on it now (but the file extension .kt is hidden here). Since we configured and created a dedicated source folder for Kotlin, as you can also see above, why don’t we move the newly converted Kotlin file to the space for Kotlin? It’s just like refactoring a Java file by moving it into a new folder or package by dragging it in the project explorer. Be sure to retain the existing package name of the class in the kotlin source directory so that the project still runs.
If you only want to use Kotlin in a project, you are free to delete the java source dir completely and put all Kotlin files in the kotlin space. With that, your project will look something like this:
Now we’ll actually dive into code and see how some Kotlin language features can be used to do nifty things in an Android project.
Kotlin has a feature called type-safe builders that lets you express object creation in a style that looks declarative. It allows a syntax that looks a lot like Gradle build files. But where Gradle and Groovy are dynamically typed, Kotlin is statically typed, so the compiler will let you know if you’re assigning values to properties that don’t make sense.
The typical examples of type-safe builders show how it’s possible to build nested data structures, like XML documents. When I think Android and XML, layouts and views quickly come to mind. If Kotlin is good at building up stuff like XML programmatically, perhaps it would do well with view hierarchies. So, that’s where I started. I figured I would try to create a sort of shorthand for building view hierarchies programmatically, which is code-intensive if you’re doing it in the Java® language.
Important note: I will be referring to lambdas frequently going forward. Before continuing, be sure you understand what that means in the context of computer programming, even if not specifically for Kotlin. In short, it’s a way of expressing an anonymous function that you would pass inline to another function or assign to a variable.
The core feature of Kotlin that makes type-safe builders possible is called lambda with receiver. Let’s get straight into an example that’s actually useful. Kotlin allows you to define functions outside of classes, and that’s all I’m doing here. Also note that the names of variables come before their types, which is the opposite of the Java language.
The above function is named v for brevity as I’ll use it a lot here and in future posts, and you can call it like this:
That’s equivalent to inflating an XML layout that looks like this:
Neat! Now, if this is your first time seeing Kotlin, there’s a lot to translate into English! Here’s a few bits of Kotlin syntax to unpack:
<reified TV : View>
The word reify means “to make an abstract thing concrete”. As a Kotlin keyword on a function’s generic type, this means that you have compile-time access to the JVM Class object specified for the generic type in the body of the function. So this bit of code says that the function v makes use of a “reified” generic type named TV (think “Type of View”) which must be View or a subclass of View. The function must also be declared inline for this to work. The caller then gives TV a specific type in angle brackets when calling the function.
init: TV.() -> Unit
v takes two parameters, a Context and a lambda named init. init is special because it’s a lambda with receiver type function reference. A lambda with receiver is a block of code that requires an object of a certain type. This required object is referenced by the keyword “this” in the body of the lambda. The type of the receiver object here is the reified generic type TV.
In our specific case, function v is declaring, “I’m going to create an object of type TV, and I need you to tell me how to initialize it”. So this new TV type object becomes the receiver of the provided lambda, and the lambda is invoked by v with view.init() so it can perform some actions with the view. The “-> Unit” in the syntax is just saying that the lambda returns type Unit, which is like the type void in Java code. In other words, it returns nothing.
To summarize this lambda with receiver:
v declares a parameter called init which is a lambda with receiver for type TV.
v creates and initializes a TV type object and invokes the lambda on it to initialize it.
The lambda sees the TV type object as “this” in its chunk of code.
To reference the reified generic type TV’s implicitly available Class object in the function, you can use the expression TV::class.java. This kind of expression is a very special Kotlin feature for reified generic types that drastically reduces the amount of code you must write in functionally equivalent Java code.
At this point, I’m going to anticipate a couple more questions you might have about this function:
“Why does v take two arguments, but appear to be given only one inside the argument parenthesis?”
This is another unfamiliar syntax to Java programmers. In the Java language, all the arguments to a function always appear inside the call’s parentheses, which can be a lot of added lines if it includes an anonymous callback. But in Kotlin, there is a special syntax when a lambda is the last argument to a function. This syntax allows the lambda to appear in curly braces immediately following the parentheses of the function call. You couldput the whole thing inside the parentheses, but most of the time it’s neater this way and keeps the function call parentheses on the same line, so they’re easier to track. Also, this lambda syntax is similarly available when inlining anonymous Java objects that have a single method, such as Runnable.
“Are ‘layoutParams’ and ‘text’ some sort of variables?”
A syntax feature of a lambda with receiver is that the “this” keyword may be omitted when referencing methods and properties of “this” inside the lambda. But what exactly are layoutParams and text in the call example? These are provided by Kotlin as properties of the receiver type TV (a TextView in our example). Because TextView has methods for setLayoutParams() and setText(), Kotlin recognizes those as JavaBeans-style accessors and creates properties for them that can be accessed as if they were Java class members. So, text = “Hello” here is exactly equivalent to this.setText(“Hello”). Slick! Here’s a screenshot of Android Studio with the Kotlin plugin showing specifically what’s going on during autocomplete:
As you can see, the Kotlin plugin is pointing out to us that the property called “text” (among other properties) is derived from the underlying JavaBeans-style getter and setter methods of the TextView type receiver object.
“What is this Constructor business? Can’t we just say “new TV(context)”?”
Since the compiler doesn’t know exactly what a TV is yet in the method body of v, we can’t instantiate it using new + classname. However, we can use the reified class object (TV::class.java) to locate a Constructor that takes a Context as the single argument. It’s conventional for Android View types to have a constructor with this signature, and we’re depending on it. This Constructor object can be invoked to get a new instance of type TV, with the same effect as the new keyword in Java code. This is a reasonable price to pay for the flexibility of having a single function work for all types of views instead of creating a whole new function for each type of view you want to build. And we can optimize this a bit more later in a future part to this blog series.
That’s a whole lot of convenience for a few lines of code! If you’re new to Kotlin, you might want to go back and digest this a second time, because some of these concepts can be very foreign to Java programmers. It certainly took me a bit of studying to grok all this new stuff.
This is just the beginning of my experiment. There’s still many ways this function could be enhanced and made easier to use.