The Importance of Kotlin in Building Modern Android Apps
By: Kayvan Kaseb
Tags: Kotlin Programming, Android Apps, Android App Development, Kotlin, Android

The picture is provided by Unsplash

As a matter of fact, Kotlin is a general-purpose, statically typed, and open-source programming language. A recent study by Google represents that developers who adopt Kotlin are, on average, 50% more likely to be satisfied with their programming language. Besides, currently, more than 70% of the top 1000 apps in the Google Play store include Kotlin code. This article will discuss some critical concepts, features, and best practices in using Kotlin for building modern Android apps.

Introduction and Overview

Basically, Kotlin is a general-purpose, statically typed, and open-source programming language. It runs on Java Virtual Machine (JVM), and also it can be used to develop Android apps, server-side apps and much more. Kotlin was developed by JetBrains team. A project was started in 2010 to develop the language, and first released in February 2016 officially. Since the release of Android Studio 3.0 in October 2017, Kotlin has been included as an alternative approach to the standard Java compiler. A recent survey by Google represents that developers who adopt Kotlin are, on average, 50% more likely to be satisfied with their programming language. The same study illustrates that 60% of Android Pro developers are using Kotlin in their codebase. Also, now, more than 70% of the top 1000 apps in the Google Play store contain Kotlin code. Currently, over 60 of Google’s apps are using Kotlin. Google’s large internal codebase counts over two million lines of Kotlin code. Eventually, Google recently started using Kotlin for server-side code, too. There are some significant reasons and advanced features can be mentioned for offering this language to Android developers as follows:

Expressiveness: The Kotlin language allow you to focus on expressing your ideas and write less boilerplate code.

2. Safety: Kotlin’s strong type system helps prevent runtime issues, such as null pointer exceptions and string format issues. In fact, Google has indicated that among the top 1000 apps on Google Play, those that use Kotlin have 20% fewer crashes per user than those that do not.

3. Interoperability: Android developers have been writing their apps using the Java programming language for many years, and there is a wealth of existing libraries written in Java. It would be difficult to get started with Kotlin without seamless interop with the Java programming language. Kotlin is 100% interoperable with the Java programming language. Therefore, you can have as little or as much of Kotlin in your Android project as you want.

4. Structured Concurrency: The Kotlin coroutines and structured concurrency can be able to solve one of the most difficult problems for developers when writing Android apps, running asynchronous operations, in a unique way.

The following sections will consider some best practices and new features in Kotlin for modern Android development.

Kotlin Coroutines

In fact, in Android 11, Google has marked Async class as deprecated. So, the question is what should you use instead? Developers have turned to use various custom solutions, such as RxJava, Thread, Executors, and ListenableFuture. However, with Kotlin, there is one more contender and that is Coroutines. In short, Kotlin coroutines allow you to simplify asynchronous programming in your Android apps. This means instead of having a number of callbacks in your code, you can write your code in a more sequential way. Coroutines were added to Kotlin in version 1.3, and are established on some concepts from other programming languages. In one of Google’s recent surveys, Google has mentioned that over 50% of professional developers who use coroutines are seeing increased productivity.

As a result, Google has recently announced that coroutines are the recommended solution for async code on Android. There are some reasons for this approach briefly as follows: 1. Structured concurrency 2. Non-blocking sequential code 3. Cancellation propagation 4. Natural exception handling.

Structured concurrency helps developers scope the work to the application lifecycle and prevent memory leaks. Furthermore, callback-free code is easier to read and less error prone, while built-in support for cancellation and natural exception handling helps ensure the error case is managed appropriately. To enter the world of coroutines, Google has implemented coroutine scopes that allow you to run async code inside ViewModels. Within these scopes you can make use of the coroutines support in various Jetpack libraries. For instance, LoginViewModel is blocking the UI thread when making the network request. The simplest solution to move the execution off the main thread is to create a new coroutine and execute the network request on an I/O thread:

class LoginViewModel(

private val loginRepository: LoginRepository

): ViewModel() {



fun makeLoginRequest(username: String, token: String) {

viewModelScope.launch {

val jsonBody = "{ username: \"$username\", token: \"$token\"}"

val result = try {

loginRepository.makeLoginRequest(jsonBody)

} catch(e: Exception) {

Result.Error(Exception("The request failed"))

}

when (result) {

is Result.Success<LoginResponse> -> // Happy path

else -> // Show error in UI

}

}

}

}

Here, viewModelScope is a predefined CoroutineScope that is included with the ViewModel KTX extensions because all coroutines have to run in a scope. If the ViewModel is destroyed because the user is navigating away from the screen, ViewModelScope is automatically cancelled, and all running coroutines are canceled as well. Besides, launch is a function that creates a coroutine and dispatches the execution of its function body to the corresponding dispatcher. Finally, Dispatchers.IO shows that this coroutine should be executed on a thread reserved for I/O operations. In general, Dispatchers define thread pools to launch your Kotlin Coroutines in.

Coroutines and Jetpack

Room: You can easily access database without blocking the main thread through coroutines. All data access statements such as insert, update, delete, and query, support a suspend version and ensure that the database is accessed on a background thread for you. Additionally, database queries allow you to return Flow as well, not just the suspend functions. So, you can be able to notice the changes in your database as they occur.

In coroutines, a flow is a type that can emit multiple values sequentially, as opposed to suspend functions that return only a single value. For example, you can use a flow to receive live updates from a database.

WorkManager: In the meantime, longer running tasks are often modeled through jobs inside WorkManager. With CoroutineWorker you can easily model job cancellation. If the database and HTTP client provide suspending versions of their APIs, we have suspending calls all the way down. Everything seems sequential and is readable. The functionality, for both Room and WorkManager, is provided via extension functions and KTX artifacts. However, in some new libraries, Google has started with coroutines from the basis. A proper example could be the new Paging 3.0 library. To define a source for the list of users you will require to show on the screen, you would implement a PagingSource and override the load method. As load is a suspend function, you can easily call other suspend functions like a backend call. Next, Paging allows you to work with the flow of PagingData. This gives you more flexibility and finer-grained control of the data you end up displaying.

DataStore: Another important library, which is built on coroutines and Flow is DataStore. To be exact, DataStore is a new and improved data storage solution aimed at replacing SharedPreferences.

Jetpack DataStore is a data storage solution that allows you to store key-value pairs or typed objects with protocol buffers. DataStore uses Kotlin coroutines and Flow to store data asynchronously, consistently, and transactionally.

Thus, DataStore provides two different implementations:

Proto DataStore: stores data as instances of a custom data type using protocol buffers.

2. Preference DataStore, this stores and accesses data using key-value pairs.

All in all, data is stored asynchronously using coroutines, and it can be retrieved using Flow.

Jetpack Compose and Kotlin

Fundamentally, if we want to consider the Compose’s project structure deeply, we can notice that Jetpack Compose uses a custom Kotlin plugin to transform the declarative UI functions you write, into the app’s UI elements.

Jetpack Compose is a modern toolkit for building native Android UI. Jetpack Compose simplifies and accelerates UI development on Android with less code, powerful tools, and intuitive Kotlin APIs.

At the moment, Jetpack Compose is currently in alpha. So, the API surface is not yet finalized completely.

Kotlin for library authors

If you are library author, performance can play a key role for you. Therefore, there are several tools that can be helpful for you as follows:

1. Explicit API mode in Kotlin 1.4: If you enable this mode, the compiler helps you be intentional about the public API you are exposing when writing a library. In this mode, you have to explicitly declare visibility modifiers and type satisfactions. To enable this mode, you should update your Gradle file for adding the explicit API file. Also, depending on your configuration, these explicit APIs can produce errors or warnings.

2. Kotlin Symbol Processing (KSP): This is an advanced project from Google. Google’s data shows that many Kotlin builds are significantly slowed down by Annotation Processors. The Kotlin Tool Chain requires to accomplish lots of activities to make these run seamlessly between Java and Kotlin, and it can cause performance concerns. Therefore, Google has been working on Kotlin Symbol Processing or KSP as an alternative to this. Instead of using KAPT, developers can now build light-weight plugins that run as part of the Kotlin Compilation Process. KSP allows for incremental resolution of symbols and from porting some existing AnnotationProcessors. Google has mentioned that this feature has 30 to 40 % faster compilations. KSP comes with a rich set of APIs and offers access to all Kotlin symbols, including ones that are not available in the Java such as properties and function types. KSP is multiplatform ready. This means you can write your Symbol Processor once, and use it on all the target platforms that your project uses. However, KSP is still in developer preview and not quite ready for production usage.

Kotlin Symbol Processing (KSP) is an API that you can use to develop lightweight compiler plugins. KSP provides a simplified compiler plugin API that leverages the power of Kotlin while keeping the learning curve at a minimum. KSP is designed to hide compiler changes, minimizing maintenance efforts for processors that use it.

3. R8 Kotlin Metadata support: When you use Android Studio 3.4 or Android Gradle plugin 3.4.0 and higher, R8 is the default compiler that converts your project’s Java bytecode into the DEX format, which runs on the Android platform. In addition, Kotlin metadata is extra information stored in annotations in Java class files produced by the Kotlin JVM compiler. This metadata specifies which Kotlin language construct a given class or method in the class file corresponds to. For instance, Kotlin metadata allows the Kotlin compiler to recognize that a method in a class file is a Kotlin extension function. Now, R8 can add support for Kotlin Metadata rewriting. Kotlin Metadata is used by the compiler when linking against libraries written in Kotlin. Thus, the compiler can recognize, for example, extension functions and suspend functions, which do not exist natively in JVM. Furthermore, Kotlin Metadata is needed for Kotlin reflection calls at runtime. Previously, R8 was unaware of Kotlin Metadata. So, when you shrink a library, it can remove or destroy that metadata, making it no longer useable. By using new versions, it will correctly process all the Kotlin Metadata information, making it useful for library authors wanting to process their libraries with R8, as well as for compiling code that uses Kotlin reflect.

Jetpack KTX

Android KTX is a set of extensions to the Android framework aims at making your development with Kotlin more clear, pleasant, and idiomatic. Android KTX provides an appropriate API layer on top of both Android framework and Support Library to make writing your Kotlin code much more natural. Google has had several releases including contributions from the community. They also changed the name to Core KTX as part of Jetpack, and it divided into modules. This set of libraries aimed at accelerating Android development. The core-ktx library consists of extensions to the features and functionality of the framework. In other words, Android KTX has one core module and a few other modules, which are more domain-specific. Classes from AndroidX such as FragmentManager, Collection, LiveData reactive streams, and the new Navigation component have associated KTX artifacts.

In conclusion

As you know, since the release of Android Studio 3.0 in October 2017, Kotlin has been included as an alternative approach to the standard Java compiler. A recent survey illustrates that 60% of Android Pro developers are using Kotlin in their codebase. This essay considered some new features and best practices in using Kotlin for Android developers.