Why Kotlin Is The Best Language For Android Development

Why Kotlin Is The Best Language For Android Development

Kotlin is the first language officially supported by the Google for Android development other than Java itself. This alone is a significant accomplishment and a clue that Kotlin is a good language for Android. Another good sign is the reception of Android developers themselves to the announcement.

In this article we are going to explain the reasons why Kotlin is particularly good for Android development looking at two different aspects:

  1. we describe the features of Kotlin which are particularly relevant for Android development
  2. we look at the ecosystem around the language itself: things such as the IDE and the JVM on Android

Considering all of this, there is only one possible reason for not using Kotlin in new Android projects: you do not know the language. Do not worry, we can help you learning Kotlin.

100+ Resources to Learn Kotlin

Receive over 100 resources to learn Kotlin in the right way.

You will receive the guide in your inbox, ready to be read on any device you want, when you have the time.


Language Features And Libraries

Applications for Android have some specific common features, typical of applications with a graphical UI. For instance, they make heavy use of asynchronous calls. Kotlin offers good support for them and even one or two libraries that can help when the language itself cannot.

Deep Interoperability

In a previous article we have talked about the great interoperability between Java and Kotlin which allows a smooth transition between the two or even a peaceful and productive co-existence. This interoperability involve all aspects: from the language itself to the bytecode produced. Something which is fundamental to allow reuse of important libraries that analyze it.

When it comes to the language itself you can find on the Kotlin documentation a complete list of the features for Java support. This interoperability is smart and deep. For instance Kotlin also support some conventions of Java development, as the following example based on getters and setters from the documentation.

import java.util.Calendar

fun calendarDemo() {
    val calendar = Calendar.getInstance()
    if (calendar.firstDayOfWeek == Calendar.SUNDAY) {  // call getFirstDayOfWeek()
        calendar.firstDayOfWeek = Calendar.MONDAY       // call setFirstDayOfWeek()
    }
}

This is great for Android development because the SDKs are obviously still made for Java. Thus by having such a great interoperability you can still write productive Kotlin code when you must use Java libraries.

Function Arguments

In Kotlin function arguments can be named and have default values. This simplifies reading and understanding at the call site and allows to limit the number of function overloads. Because you do not have to make a new function for every argument that is optional, you just put a default value on the definition.

Let’s compare definitions in Java and Kotlin.

 // Java
void drawText(int x, int y, int size, int spacing, String text)
{ [..] }

// Kotlin
fun drawText(x: Int = 0, y: Int = 0, size: Int = 20, spacing: Int = 0, String: text)
{ [..] }

And calling the same function in Java and Kotlin.

// Java
drawText(50, 200, 20, "hello");

// Kotlin
// using default values
drawText("kneel in front of the Kotlin master!")

// using named arguments
drawText(10, 25, size = 20, spacing = 5, "hello")

Nullable Types

In Kotlin you need to explicitly say that a variable can have a null value. By default it cannot. And this allows you app to avoid the common and dreaded NullPointerException at runtime, because most mistakes are caught by the compiler at compilation time. Null references are so risky that the creator of the first language with null reference call it the Billion Dollar Mistake.

var text: String = null // it does not compile
var unsafeText: String? = null // ok 

Kotlin takes advantage of the nullability or, at the opposite, the safeness of types at all levels. For instance, it is taken into consideration during checks.

unsafeText.length // it does not compile

if (unsafeText != null) {
  unsafeText.length // it works, but it is not the best way
}

After you have checked that a nullable type is currently not null you can use the variable in the same way as it is were not nullable, because inside the block it is safe to use. Of course this also looks cumbersome, but there is a better, suggested way, that is equivalent, but more concise.

unsafeText?.length // it works

The safe call operator (?.) guarantees that the variable will be accessed only if unsafeText it is not null.

Nullable types are particularly useful in Android because null is widely used. This can lead to a lot of bugs, but in Java you have not alternatives. Even looking at the official APIs you can see the @NotNull annotation all over the place.

In fact null it is used for several reasons, from performance to the lifecycle of the application that might require certain steps to be executed before you can properly initialize a variable. In such cases you might think that you cannot avoid using null, but you would be wrong. There are several ways to do it, including using late initialization or lazy initialization.

Lazy And Late Initialization

Late initialization works only for variable properties inside the body of a class. The variable cannot be of a null type. You add the modifier lateinit and then inside a method you initialize the variable. If you access the variable before initializing it you get a special exception that clearly indicate what you did wrong. The modifier lateinit was introduced to support dependency injection, but it can be useful in many other scenarios.

If you need a costant value instead you can use the lazy() function to delegate initialization to a function. Lazy accepts a lambda that is executed the first time the variable it is accessed. The function initialize the variable and return its value. The following times the variable is accessed the function is not executed, only the value is returned.

val computedValue: String by lazy {
    println("I am executed only the first time!")
    "A Value That Will Be Subsequently Remembered"
}

Lazy is useful when the computation of the value is costly and it does not change.

Data Classes

You need to use classes to group together semantically connected variables. In an Android app they are frequently used to represent the model of the application. The class just need to hold values, but typically you need a few standard methods to manage the data, getting and setting values of properties, etc. And you also have to update them every time you change the data.

Kotlin gives all that you need automatically, simply by using the data keyword in front of the class definition.

data class User(val name: String, var password: String, val age: Int)

That’s it. Now you get for free:

  • getters and setters (these only for variable references) to read and write all properties
  • component1() .. componentN() for all properties in the order of their declaration. These are used for destructuring declarations.
  • equals(), hashCode() and copy() to manage objects (ie. compare and copy them)
  • toString() to output an object in the human readable form Name_of_the_class(Name_of_the_variable=Value_of_the_variable, [..])"

For example, given the previous data class User

val john = User("john","secret!Shhh!", 20)
 
println(john.component1()) // it prints "john"
// mostly used automagically in destructuring declaration like this one
val (name, password, age) = john
println(age) // it prints 20

println(john) // it prints "User(name=john, password=secret!Shhh!, age=20)"

Is it mind blowing? No.

Is it a very useful thing? Yes, it is. It saves time and it allows easier changes to the model of an Android application, since you do not need to write custom functions to compare objects yourself.

Eliminating Utility Classes

Android applications need utility classes to add new features on existing classes or perform common operations specific to the app. Kotlin offers a couple of way to get rid of them: extensions methods and the possibility of using top-level functions without defining a class.

It is important to remember that both are syntactic sugar. Using extensions methods to extend a class you cannot access private or protected members of that class.

// extension method
fun String.bePolite() : String {
  return this + ", please"
}

val ask = "Pass me the salt"
println(ask.bePolite()) // It prints "Pass me the salt, please"

And if you want to use top-level functions in Java they still are inside a generated class. The generated class name usually is based on the name of the file in which the extension method is defined, but this can be altered with annotations.

// filename polite.kt
package strings

fun checkPolite(request: String) : Boolean {
    if (request.contains("please"))
    	return true
    else
    	return false
}

// a Java file
import strings.PoliteKt;

PoliteKt.checkPolite("prove P=NP, please");

There is another feature that makes utility methods more useful: operator overloading. You cannot define custom operators, but you can very easily use standard operators for your classes. All you have to do is defining functions with specific name and then Kotlin will translate the corresponding operator in this function on the call site. For instance if you define a function plus() for your class Kotlin will translate objectOfYourClass1 + objectOfYourClass2 in objectOfYourClass1.plus(objectOfYourClass2).

Functional Features

Functional programming is not a new programming paradigm, but its success it is relatively new. This is due to the increase of situations that require a lot of concurrency and parallelism. Android applications are not the best use case for fully functional applications, but they need to use asynchronous calls for UI interactions and often to call online backend services, so they would benefit from functional features. In short, Android applications benefit from functional features in the context of imperative programming.

The most common features are higher-order functions and lambdas. Higher-order functions are functions that accept functions as arguments or return one. Lambdas are anonymous functions that can be passed around. The problem is that only with version 8 that Java started including them, so many are forced to use a library, like Retrolambda. The reason because you cannot use Java 8 is explained in the later paragraph The Java Platform On Android. This is far from ideal, because the language itself does not support them and thus many libraries cannot take advantage of them.

A language like Kotlin, that include them from the beginning, allows you to take full advantage of them.

We assume that you already know the advantages of similar functional features, so what we are going to show is an example of how well and easily you can use them in Kotlin thanks to many of its conventions.

val strings: List = listOf("one", "two", "three", "Hello", "to", "Kotlin", "and", "Me")
// we first take only the strings longer than 3
// then we transform each string in its lowercase version
// finally we join them in one string
println(strings.filter { it.length > 3 }.map { it.toLowerCase() }.joinToString())
// it prints "three, hello, kotlin"

If you familiar with C# you will notice how similar this is to LINQ. This is also noted in the official documentation. And it goes to show how pragmatic Kotlin is. Kotlin took the best out of many languages and it added some more. In this case some more is the default name it that can be used when the lambda takes one argument. It is also the chance to put the lambda out of the parentheses if it is the last argument of the function and to omit the parentheses altogether if a lambda is the only argument (eg. for filter and map).

Concise, readable and easy to use. What could you ask more?

Kotlin Android Extensions

There are also Kotlin Android Extensions that allows you, among other things, to replace the annoying and bug-ridden findViewById() calls with synthetic properties. An example to clarify, from the documentation:

// Using R.layout.activity_main from the main source set
import kotlinx.android.synthetic.main.activity_main.*

class MyActivity : Activity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        textView.setText("Hello, world!") // Instead of findViewById(R.id.textView) as TextView
    }
}

There are some libraries for Java that allows you to do something similar, but they usually requires annotations. Kotlin offers a simpler way to do it, without any extra code or runtime.

Anko

Anko is a Kotlin library which makes Android application development faster and easier. It makes your code clean and easy to read, and lets you forget about rough edges of the Android SDK for Java.

Anko is a popular library that simplifies Android development with a lot of helpers. In fact, they are too many to mention all of them here. But we can say that the library is divided in several parts:

  • Anko Commons: full of helpers for intents, dialogs and toasts, logging, resouces and dimensions…
  • Anko Layouts: a fast and type-safe way to write dynamic Android layouts
  • Anko SQLite: a query component and parser collection for Android SQLite

We are going to show an example of Anko Layouts, because it also show another useful characteristic of Kotlin: type-safe builders. These are a safer and more concise alternative to configuration files and such things to describe data with a hierarchical structure. A typical example is a XML file used to describe a UI.

Using an XML file requires you to rewrite each time for each interface the same boilerplate structure. The only thing that varies is the data itself. This is not just boring, but also error-prone, hard to read and unsafe. Because it is easy to commit a mistake. Builders in Kotlin provide a better alternative.

You can transform the following Kotlin code (and let’s not even talk about the corresponding Java version…)

val act = this
val layout = LinearLayout(act)
layout.orientation = LinearLayout.VERTICAL
val name = EditText(act)
val button = Button(act)
button.text = "Say Hello"
button.setOnClickListener {
    Toast.makeText(act, "Hello, ${name.text}!", Toast.LENGTH_SHORT).show()
}
layout.addView(name)
layout.addView(button)

…in this much better version…

verticalLayout {
    val name = editText()
    button("Say Hello") {
        onClick { toast("Hello, ${name.text}!") }
    }
}

Which creates the following interface.

Example Layout defined with Anko

Example Layout from the Anko documentation

There is even an Android Studio/Intellij IDEA plugin to preview interfaces created with Anko.

Building Kotlin Applications For Android

There are some technical aspects to consider when building Kotlin applications for Android. They are relative both to Java and the tools used to develop for Android and involve many concerns of developers other than the language itself.

The Java Platform On Android

A table and a graph representing the percentages of devices for each different version of Android

Data on the different versions of Android coming from the official documentation

Experienced Android developers will already know that the history of Java on Android is complicated. For the rest, here there is a short summary. When Android launched there was not an open-source, stable and mature version of Java, since OpenJDK was just starting. So Android was based on a modified version of Apache Harmony. But with the maturing of OpenJDK the support of companies, like IBM, for Apache Harmony diminished.

Apache Harmony supported 97% of Java 6, but the project was ended in 2010, leaving Google to support the whole codebase, both its custom part and the open-source foundation. Furthermore Oracle sued Google also because it claimed Android fractured the Java platform. So Google switched the basis of Android from Apache Harmony to OpenJDK with Android 7, which also gave Android a new higher-quality foundation.

This means that, at the moment, most of Android devices support Java 6, while the last version of Android, and the future ones, should support the latest Java version. Although one problem is that there is still a delay between the OpenJDK and Android Java support because Google must adapt OpenJDK to its custom parts.

Given that the Kotlin compiler produce bytecode compatible for Java 6, Kotlin can safely brings its features to the majority of Android devices now. Thus it is the only practical choice for a modern and productive programming language for most Android developers.

IDE And Tool Support

The official IDE supported by Google for developing Android applications is Android Studio. This is the IDE that replaced the previous one based on Eclipse and it based on the open-source (community) version of IntelliJ IDEA. IntelliJ IDEA is developed by JetBrains itself and obviously supports Kotlin. But Android Studio will natively supports Kotlin starting from version 3, currently in pre-release status. There is a Kotlin plugin for previous Android Studio versions, too.

This is part of the official support of Kotlin for Android development. But it is not the only thing. We have already seen libraries and extensions made by JetBrains for Android.

Android Studio uses Gradle for build automation and Kotlin can be used as a language for Gradle scripting.

Finally, the Android SDK supports ProGuard, a tool to optimize, remove unused methods and obfuscate Java bytecode. Given the similarity between Kotlin and Java bytecode ProGuard also works well for Kotlin. This is a good example of how deep goes the effort of JetBrains to maintain compatibility between Java and Kotlin and why they do that.

APK Limitations

Apart from Java support there are many small differences between the official JVM and the one supported by Android. One that matters particularly for Android development is the limit on the numbers of methods and fields in your application: 216, which means a bit more than 65000. The Kotlin runtime and standard library combined adds around 7000 methods, which is circa 10% of your method count. This is not an insignificant amount, but using ProGuard it can be reduced substantially, even to 42!

Furthermore it can actually be an advantage if it allows you to get rid of an alternative library. Good candidates are libraries that introduce small functional features or improve the productivity of developers, or the quality of life. The developers of App Lock managed to reduce the total method count by 10% and the total lines of code by 30% with a conversion from Java. Another app developer reached a reduction of 20% lines of code.

Also, to put things in perspective, 7000 methods are not that much compared to the ones of a library like Google Guava, that has almost 15000 methods. And let’s not even talk about the numbers of languages like the 50000 of Scala or the 30000 of Groovy. Such high numbers make them practically unusable for Android development, no matter the advantages.

There is also a limit on the size of the APK that you can upload on the Google Play Store. This limit is 100MB. Even without that artificial limit there would also to consider the limited space on the users devices and possibly the costs of transferring the APK over metered connections. So the fact that Kotlin adds only around 1MB to the debug APK, and even less to the release one, it is a good thing.

Bottom line: using Kotlin have consequences in light of APK limitations, but considering the alternatives it is a no-brainer.

Java Conversion Tool

JetBrains has done a solid job with their Kotlin plugin and its ability to auto convert Java to Kotlin. It can get your class 60–70% of the way there, leaving you with some tuning and idiomatic/stylistic things to take care of.

How we made Basecamp 3’s Android app 100% Kotlin

JetBrains developed a tool to convert Java code in Kotlin. This is a tool that can be accessed in many ways, in the online test environment, which make it useful for learning, and in the IDEs, like IntelliJ IDEA and Android Studio, which make it useful for learning and coding.

It is a very useful tool, but as most automatic conversion tools it is not perfect. Studying the results is needed for learners to understand the basics use. While it may not break your class, it does not always produce the best code, so it is also useful to study the results to modify them in the idiomatic and suggested way of using Kotlin.

Compilation Speed

The time necessary to compile Android application has been a pain point even with Java for some time, since the adoption of Gradle. With Kotlin the speed is now great, even for people that during the beta criticize it for its slowness. It is even better than Java with Retrolambda.

What does it mean great? On clean builds a Kotlin application it is slower than a Java one by around 15%. This remain true both for the first build and for subsequent builds with the Gradle daemon. But where it counts, that is to say during development when you change a few files at once before recompiling (incremental builds) it is actually faster than Java itself.

Drawbacks

The language Kotlin is already mature, but there is still work to do in the ecosytem around the language.

Annotation Support

Some advanced features like Java annotation support and reflection were not greatly supported in Kotlin up until the last few pre-release versions. A frequently requested feature used to be support for annotation processing in Kotlin. In particular many people wanted support for ButterKnife, the famous Android library that uses annotation to bind field and methods with views. There were already alternative to do the same things of ButterKnife with Kotlin, but good annotation support was needed.

Now stability and support is there, but there are still difficulties in some cases, if nothing else from configuration and changing apt with kapt. Kapt is the annotation processing tool for Kotlin that brings support for dagger, a fast dependency injector for Android, and dbflow, an ORM android database library that writes database code for you. At the moment using kapt noticeably slow compilation speed. The Kotlin ecosystem is mostly there, but there are still annoying problems to fix.

Analysis Of The Code

One way that Kotlin managed to be so well compatible with Java, and with so little overhead, is that a lot of the smart stuff of Kotlin is in the compiler and not the generated bytecode. Which means that reflection is costly and requires a specific library in addition to the runtime. You need to add kotlin-reflect which adds almost 20.000 methods to you app which is clearly very far from ideal. The workaround is to use reflection in Java or use the Java reflection support in Kotlin. For instance you can use String::class.java.methods to access the Java/JVM methods created by the Kotlin compiler.

The first option requires you to keep using Java, at least in some places, but it is guaranteed to work. The second one allows you to use exclusively Kotlin, but the results may be different from what you expect. That is because the productivity granted by Kotlin relies on operations behind the scenes. For example to allow you to use default values in Kotlin the compiler generates a Java method for every combination of arguments.

Another current problem is the lack of static analysis tools for Kotlin. It is true that the Kotlin compiler is smarter and safer than the Java one. And you can actually integrate the command line compiler in your workflow. Still this is undeniably a current weakness of Kotlin, which probably will remain for some time given that the official Kotlin parser is open-source, but tightly integrated in the compiler. Thus it is not easy to extract and reuse it.

Is Kotlin The Swift Of Android?

Kotlin and Swift logos

Kotlin and Swift started being developed roughly at the same time, but Swift was released first. So there is a certain reputation of Kotlin as The Swift Of Android. This is not so much because one inspired the other, but because both of them were developed to bring a more modern programming language to their respective operating systems. They intend to be an upgrade to their predecessors.

In that sense the languages have similar needs of keeping compatibility. At the very least, they need to keep it at the design level because they target the same environments and they surely target the same developers. They largely succeeded. And being languages developed at the same time they have also similar concerns and features, for instance they are both languages in which type inference, nullability and constant values are concerns.

So you could say that Kotlin, at least for Android, is like Swift for iOS. This is a good thing because it simplifies development and understanding. You might not have the same developer working on both the Android and iOS version of one app, but having similar languages makes easy for both teams to coordinate between them and follow the same structure. This increase productivity and reduces the risks of different bugs introduced in different versions of the same app.

Kotlin Is Better Than Swift

One important difference, though, is that, as usually happens, tools and language design of Apple is a bit of lower quality than the alternatives. This happens because Apple has really no competition in the development part. If your customers choose Apple you, the developer, have really no choice, you must work with what Apple gives you.

In fact a common criticism is the instability of Xcode, compared to Android Studio. Also Swift development may have been too quick: there have been already three versions of Swift in three years and each version introduced breaking changes. While it is better to have an updated language than a stale one, a language that moves too quickly it is also not ideal for developer productivity.

So we would say that Kotlin for Android is better than Swift for iOS: it has better tool support and it is a more stable language.

Summary

Kotlin is a language designed to be easy to use and extremely productive. It brings to the Java world many of the modern features that it lacks and it adds some new ones that fits the style and needs of experienced Java developers. It does the same for Android development and on top of that adds libraries and tools to simplify common development patterns for the mobile OS.

It is not an accident that Kotlin is loved by Android developers and officially supported by Google. It works great and it is the best programming language for Android development that you can use right now.

JetBrains started focusing on supporting Android developers and got great popularity among them. Now it can use that traction to challenge Java in other areas. However every Android developer can now benefit from those investments and enjoy the results.

What are you waiting for? What is your reason for not using Kotlin for Android development?

0 replies

Leave a Reply

Want to join the discussion?
Feel free to contribute!

Leave a Reply

Your email address will not be published. Required fields are marked *