Why Kotlin for Android Development?
Kotlin is a great fit for developing Android applications, bringing all of the advantages of a modern language to the Android platform without introducing any new restrictions:
- Compatibility: Kotlin is fully compatible with JDK 6, ensuring that Kotlin applications can run on older Android devices with no issues. The Kotlin tooling is fully supported in Android Studio and compatible with the Android build system.
- Performance: A Kotlin application runs as fast as an equivalent Java one, thanks to very similar bytecode structure. With Kotlin’s support for inline functions, code using lambdas often runs even faster than the same code written in Java.
- Interoperability: Kotlin is 100% interoperable with Java, allowing to use all existing Android libraries in a Kotlin application. This includes annotation processing, so databinding and Dagger work too.
- Footprint: Kotlin has a very compact runtime library, which can be further reduced through the use of ProGuard. In a real Application, the Kotlin runtime adds only a few hundred methods and less than 100K to the size of the .apk file.
- Compilation Time: Kotlin supports efficient incremental compilation, so while there’s some additional overhead for clean builds, Faster Than Java.
- Learning Curve: For a Java developer, getting started with Kotlin is very easy. The automated Java to Kotlin converter included in the Kotlin plugin helps with the first steps. Kotlin koans offer a guide through the key features of the language with a series of interactive exercises.
-
From Java To Kotlin
-
Java
System.out.print("Ganesh Divekar"); Kotlin
print("Ganesh Divekar")
Java
String name = "Ganesh Divekar";
Kotlin
var name = "Ganesh Divekar"
Java
String otherName; otherName = null;
Kotlin
var otherName : String? otherName = null
Java
if(text != null){ int length = text.length(); }
Kotlin
text?.let { val length = text.length }
Java
String firstName = "Ganesh"; String lastName = "Divekar"; String message = "My name is: " + firstName + " " + lastName;
Kotlin
val firstName = "Ganesh" val lastName = "Divekar" val message = "My name is: $firstName $lastName"
Java
String text = "First Line\n" + "Second Line\n" + "Third Line";
Kotlin
val text = """ |First Line |Second Line |Third Line """.trimMargin()
Java
String text = x > 5 ? "x > 5" : "x <= 5";
Kotlin
val text = if (x > 5) "x > 5" else "x <= 5"
Java
if(object instanceof Car){ } Car car = (Car) object;
Kotlin
if (object is Car) { } var car = object as Car
Java
if(object instanceof Car){ Car car = (Car) object; }
Kotlin
if (object is Car) { var car = object // smart casting }
Java
if(score >= 0 && score <= 300 ){}
Kotlin
if (score in 0..300) { }
Java
int score = // some score; String grade; switch (score) { case 10: case 9: grade = "Excellent"; break; case 8: case 7: case 6: grade = "Good"; break; case 5: case 4: grade = "Ok"; break; case 3: case 2: case 1: grade = "Fail"; break; default: grade = "Fail"; }
Kotlin
var score = // some score var grade = when (score) { 9, 10 -> "Excellent" in 6..8 -> "Good" 4, 5 -> "Ok" in 1..3 -> "Fail" else -> "Fail" }
Java
for (int i = 1; i <= 10 ; i++) { } for (int i = 1; i < 10 ; i++) { } for (int i = 10; i >= 0 ; i--) { } for (int i = 1; i <= 10 ; i+=2) { } for (int i = 10; i >= 0 ; i-=2) { } for (String item : collection) { } for (Map.Entry<String, String> entry: map.entrySet()) { }
Kotlin
for (i in 1..10) { } for (i in 1 until 10) { } for (i in 10 downTo 0) { } for (i in 1..10 step 2) {} for (i in 10 downTo 1 step 2) {} for (item in collection) {} for ((key, value) in map) {}
Java
final List<Integer> listOfNumber = Arrays.asList(1, 2, 3, 4); final Map<Integer, String> keyValue = new HashMap<Integer, String>(); map.put(1, "Ganesh"); map.put(2, "Divekar"); map.put(3, "Insider"); // Java 9 final List<Integer> listOfNumber = List.of(1, 2, 3, 4); final Map<Integer, String> keyValue = Map.of(1, "Ganesh", 2, "Divekar", 3, "Insider");
Kotlin
val listOfNumber = listOf(1, 2, 3, 4) val keyValue = mapOf(1 to "Ganesh", 2 to "Divekar", 3 to "Insider")
Java
// Java 7 and below for (Car car : cars) { System.out.println(car.speed); } // Java 8+ cars.forEach(car -> System.out.println(car.speed)); // Java 7 and below for (Car car : cars) { if(car.speed > 100) { System.out.println(car.speed); } } // Java 8+ cars.stream().filter(car -> car.speed > 100).forEach(car -> System.out.println(car.speed));
Kotlin
cars.forEach { println(it.speed) } cars.filter { it.speed > 100 } .forEach { println(it.speed)}
Java
void doSomething() { // logic here }
Kotlin
fun doSomething() { // logic here }
Java
void doSomething(int... numbers) { // logic here }
Kotlin
fun doSomething(vararg numbers: Int) { // logic here }
Java
int getScore() { // logic here return score; }
Kotlin
fun getScore(): Int { // logic here return score } // as a single-expression function fun getScore(): Int = score
Java
int getScore(int value) { // logic here return 2 * value; }
Kotlin
fun getScore(value: Int): Int { // logic here return 2 * value } // as a single-expression function fun getScore(value: Int): Int = 2 * value
Java
public class Utils { private Utils() { // This utility class is not publicly instantiable } public static int getScore(int value) { return 2 * value; } }
Kotlin
class Utils private constructor() { companion object { fun getScore(value: Int): Int { return 2 * value } } } // other way is also there object Utils { fun getScore(value: Int): Int { return 2 * value } }
Java
public class Developer { private String name; private int age; public Developer(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Developer developer = (Developer) o; if (age != developer.age) return false; return name != null ? name.equals(developer.name) : developer.name == null; } @Override public int hashCode() { int result = name != null ? name.hashCode() : 0; result = 31 * result + age; return result; } @Override public String toString() { return "Developer{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
Kotlin
data class Developer(var name: String, var age: Int)
Java
public class Utils { private Utils() { // This utility class is not publicly instantiable } public static int triple(int value) { return 3 * value; } } int result = Utils.triple(3);
Kotlin
fun Int.triple(): Int { return this * 3 } var result = 3.triple()
Installing the Kotlin Plugin in Android Studio
The very first thing you need to do is add Kotlin support to your Android Studio installation.
Before we get started, make sure you’re running the most recent, stable version of Android Studio, as you’re more likely to encounter bugs with the Kotlin plugin on experimental versions of Android Studio. It’s also worth opening the SDK Manager and checking whether updates are available for any of the packages you’ve installed.
Once you’re confident that your development environment is up to date, you’re ready to install the Kotlin plugin. Launch Android Studio and you should see the Welcome to Android Studio window—if this window doesn’t appear, then close Android Studio completely and relaunch it.
Give the Configure icon a click, and then select Plugins from the subsequent dropdown.
Click the Install JetBrains plugins… button.
Select Kotlin from the menu, and then click the green Install button. You’ll need to restart your IDE before the Kotlin plugin becomes active, so either click the Restart Android Studio button that appears or restart your IDE manually.
Configuring Your Project to Use Kotlin
At this point, your IDE can understand and run Kotlin code, but you’ll still need to configure Kotlin every time you want to use it in a new project. Let’s create a new project and configure that project to use Kotlin now. Create a new project with the settings of your choice, but for the sake of simplicity, select Empty Activity when prompted.
Thanks to the Kotlin plugin, configuring a project to use Kotlin couldn’t be simpler: just select Tools from the Android Studio toolbar, followed by Kotlin and Configure Kotlin in Project.
This opens a popup where you can choose to configure Kotlin for:
- all modules
- all modules containing Kotlin files
- or a single, named module
Since I’m only going to use Kotlin code in my project, I opted for All modules. You can also choose which version of Kotlin you want to use—typically, this will be the latest version.
Alternatively, you can configure Kotlin by selecting Help from the Android Studio menu bar, followed by Find Action… In the Find Action bar, start typing Configure Kotlin in Project, and then select this option when it appears.
The Configure Kotlin in Project option makes a number of tweaks to your project’s build.gradle files, so let’s take a closer look at how these files have changed. Open your project-level build.gradle file—it should look something like this:
-
buildscript {
//Declares the version of Kotlin that you’re using. You’ll notice that the version of Kotlin is mentioned in both the buildscript classpath and in your project’s compile dependencies - the version number must be the same in both places//
ext.kotlin_version =
'1.0.5-2'
repositories {
jcenter()
}
dependencies {
classpath
'com.android.tools.build:gradle:2.2.2'
//Declares the Kotlin Gradle plugin as a classpath dependency//
classpath
"org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
allprojects {
repositories {
jcenter()
}
}
Now, let’s take a look at your module-level build.gradle file:
-
apply plugin:
'com.android.application'
//Applies the Kotlin Android plugin//
apply plugin:
'kotlin-android'
android {
compileSdkVersion
25
buildToolsVersion
"24.0.0"
defaultConfig {
applicationId
"com.jessicathornsby.kotlinexample"
minSdkVersion
21
targetSdkVersion
25
versionCode
1
versionName
"1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile(
'proguard-android.txt'
),
'proguard-rules.pro'
}
}
//Although Gradle will compile any Kotlin files it finds in src/main/java, it’s good practice to store your Kotlin files in a dedicated Kotlin directory. Here, you can see that the Kotlin plugin has added a src/main/kotlin declaration to build.gradle, but note that it hasn’t actually created this directory, so we’ll create it ourselves later in this article//
sourceSets {
main.java.srcDirs +=
'src/main/kotlin'
}
}
dependencies {
compile fileTree(dir:
'libs'
, include: [
'*.jar'
])
androidTestCompile(
'com.android.support.test.espresso:espresso-core:2.2.2'
, {
exclude group:
'com.android.support'
, module:
'support-annotations'
})
compile
'com.android.support:appcompat-v7:25.0.1'
testCompile
'junit:junit:4.12'
//Adds the Kotlin Standard Library as a project dependency//
compile
"org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
}
repositories {
mavenCentral()
}
Finally, sync your changes either by clicking Sync Now from the popup that appears or by clicking the Sync Project with Gradle Files icon in Android Studio’s toolbar.
Convert Any Java File to Kotlin
One feature of the Kotlin plugin that’s particularly useful for Kotlin newcomers is its ability to convert any Java source file to Kotlin, while maintaining full runtime compatibility.
Being able to see exactly how any Java file would translate into Kotlin is ideal for helping you learn the language, but it can also come in useful throughout your Kotlin journey—if you’re ever struggling to work out how to write something in Kotlin, you can always write it in Java and then use this feature to convert that code into Kotlin.
Let’s convert our project’s MainActivity file into a Kotlin source file. There are two ways of invoking the Kotlin plugin’s Convert Java File to Kotlin File action, so either:
- Select your MainActivity file, and then select Code from Android Studio’s menu bar, followed by Convert Java File to Kotlin File.
- Or select Help from the Android Studio menu bar, followed by Find Action. In the subsequent popup, start typing Convert Java file to Kotlin file and then select this option when it appears. Note, you can also launch the Find Action popup with a keyboard shortcut: if you’re on a Mac, press the Command-Shift-A keys, and if you’re on Windows or Linux then press Control-Shift-A.
Just be aware that, depending on the complexity of your code, the conversion may not always be 100% accurate, so you should always check your converted code for errors.
Your newly-converted MainActivity should look something like this:
-
import
android.support.v7.app.AppCompatActivity
import
android.os.Bundle
class
MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super
.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
}
You’ll also notice that the file’s extension has changed, transforming from MainActivity.java to MainActivity.kt.
This may be a simple
Activity
, but these few lines illustrate some key characteristics of the Kotlin syntax. Since this is our first look at some actual Kotlin code, let’s pick this class apart line by line.Understanding Kotlin Syntax
In Kotlin, you declare classes using the keyword
class
, exactly like in Java. However, in Kotlin, classes (and methods) are public and final by default, so you can create a class simply by writingclass MainActivity
.When it comes to extending a class, you replace Java’s
extends
with a colon, and then attach the name of the parent class. So in the first line of our MainActivity.kt file, we’re creating a public, final class called MainActivity that extendsAppCompatActivity
: -
class
MainActivity : AppCompatActivity() {
The Java equivalent would be:
-
public
class
MainActivity
extends
AppCompatActivity {
If you do want to override a class or method, then you’ll need to explicitly declare it as open or abstract.
In Kotlin, functions are defined using the
fun
keyword, followed by the function name and the parameters in brackets. In Kotlin, the function’s name comes before its type: -
override fun onCreate(savedInstanceState: Bundle?) {
This is the opposite of Java, where type comes before name:
-
public
void
onCreate(Bundle savedInstanceState)
Note that we’re not specifying that this method is final, as in Kotlin all methods are final by default.
The rest of this Activity looks pretty similar to Java. However, these few lines do illustrate another key characteristic of Kotlin:
-
super
.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
In Kotlin you don’t need to finish your lines with semicolons, hence the absence of colons in the above snippet. You can add colons if you really want to, but your code will be cleaner and easier to read without them.
Now that we’ve deciphered our MainActivity.kt file, let’s move it to its proper home. Since the Kotlin plugin went to the trouble of adding a src/main/kotlin declaration to our build.gradle file, let’s actually create this directory. This step isn’t mandatory, but keeping your Kotlin files in a dedicated directory will make for a much cleaner project.
In Android Studio’s Project Explorer, Control-click your project’s Main directory and select New from the menu that appears, followed by Directory. Name this directory kotlin and then click OK.
If you’re struggling to spot your project’s main directory, then open the little dropdown in the upper-left of the Project Explorer and select Project. You should now have no problems spotting that elusive src/main directory.
Once you’ve created a dedicated Kotlin directory, drag your MainActivity.kt file into it. Just be sure to retain your MainActivity.kt file’s existing package name so that your project still runs.
Also, if you’re only going to use Kotlin in this project, then you may want to delete the Java directory, rather than cluttering up your project with empty and unnecessary directories.
Since Kotlin compiles to bytecode, an application that’s written in Kotlin feels exactly the same as an application that’s written in Java, so try installing this app on your Android device or a compatible AVD—it should feel as if nothing has changed.
Creating Extra Kotlin Files
If you continue working with Kotlin in your project, then sooner or later you’re going to need to start creating new Kotlin files rather than simply converting existing Java ones.
To create a Kotlin file, Control-click your app/src/main/kotlin directory and select New > Kotlin Activity.
Give your class a name and select class from the dropdown menu. Your new class should look something like this:
class
SecondActivity
{
}
At this point, your Activity is empty. To get to the point where you can start adding some real functionality, you’ll need to complete a few steps. Firstly, add the
import
statements you want to use. The only difference between import statements in Kotlin and import statements in Java is that you don’t need to finish each line with a semicolon. For example: -
import
android.app.Activity
import
android.os.Bundle
import
android.app.Activity
You’ll then need to specify the class you’re extending, using the same format we saw in our MainActivity.kt file:
class
SecondActivity : Activity() {
}
Next, you need to override the Activity’s
onCreate
method:You can now add whatever functionality you want to this Activity (and in the next section, I’ll show you how to use Kotlin extensions to manipulate UI widgets, so this may be a good place to start), but one last bit of setup you need to complete is declaring your Kotlin Activity in your Manifest. This follows exactly the same formula as declaring a new Java Activity, for example:
-
<
activity
android:name
=
".SecondActivity"
android:label
=
"@string/second"
android:parentActivityName
=
".MainActivity"
>
<
meta-data
android:name
=
"android.support.PARENT_ACTIVITY"
android:value
=
".MainActivity"
/>
</
activity
>
Kotlin Android Extensions: Wave Goodbye to
findViewById
Now that we’ve mastered the basics, let’s take a closer look at what Kotlin is really capable of—starting with a feature that can really cut the amount of boilerplate code you need to write.
In Android, every time you want to work with any
View
in an Activity, you need to use thefindViewById
method to obtain a reference to that View. This makesfindViewById
one of the most important, but also one of the most frustrating bits of code that you’ll find yourself writing over and over, and over again in your Android projects. ThefindViewById
method is a huge source of potential bugs, and if you’re working with multiple UI elements in the same Activity, then all thosefindViewById
s can really clutter up your code, making it difficult to read.While there are a number of libraries, such as Butter Knife, that aim to remove the need for
findViewById
s, these libraries still require you to annotate the fields for each View, which can lead to mistakes and still feels like a lot of effort that would be better invested in other areas of your project.The Kotlin Android Extensions plugin (which has recently been incorporated into the standard Kotlin plugin) promises to make
findViewById
a thing of the past, offering you the benefits of the aforementioned libraries without the drawback of having to write any additional code or ship an additional runtime.You can use Kotlin extensions to import
View
references into your source files. At this point the Kotlin plugin will create a set of “synthetic properties” that enable you to work with these views as though they were part of your activity—crucially, this means you no longer have to usefindViewById
to locate eachView
before you can work with it.To use extensions, you’ll need to enable the Kotlin Android Extensions plugin in each module, so open your module-level build.gradle file and add the following:
-
apply plugin:
'kotlin-android-extensions'
Sync these changes by clicking the Sync Now popup.
You can then import the references to a single
View
, using the following format: -
import
kotlinx.android.synthetic.main.<layout>.<view-id>
For example, if your acitivity_main.xml file contained a
TextView
with the IDtextView1
, then you’d import the reference to this view by adding the following to yourActivity
: -
import
kotlinx.android.synthetic.main.activity_main.textView1
You’d then be able to access
textView1
within this activity using its ID alone—and without afindViewById
in sight!Let’s take a look at extensions in action, by adding a
TextView
to our activity_main.xml file, importing it into our MainActivity.kt file, and using extensions to set theTextView
’s text programmatically.Start by creating your
TextView
: -
<?
xml
version
=
"1.0"
encoding
=
"utf-8"
?>
android:id
=
"@+id/activity_main"
android:layout_width
=
"match_parent"
android:layout_height
=
"match_parent"
android:paddingBottom
=
"@dimen/activity_vertical_margin"
android:paddingLeft
=
"@dimen/activity_horizontal_margin"
android:paddingRight
=
"@dimen/activity_horizontal_margin"
android:paddingTop
=
"@dimen/activity_vertical_margin"
tools:context
=
"com.jessicathornsby.myapplication.MainActivity"
>
<
TextView
android:id
=
"@+id/myTextView"
android:layout_width
=
"wrap_content"
android:layout_height
=
"wrap_content"
/>
</
RelativeLayout
>
You can then import the
TextView
into your MainActivity.kt, and set its text using its ID only: -
import
android.support.v7.app.AppCompatActivity
import
android.os.Bundle
import
kotlinx.android.synthetic.main.activity_main.myTextView
class
MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super
.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
myTextView.setText(
"Hello World"
)
}
}
Note, if you want to work with multiple widgets from the same layout file, then you can import the entire contents of a layout file in one fell swoop, using the following formula:
import
kotlinx.android.synthetic.main.<layout>.*
For example, if you wanted to import all the widgets from your activity_main.xml file, then you’d add the following to your Activity:
-
kotlinx.android.synthetic.main.activity_main.*
-
Cheers….!!!!