paint-brush
The Wormhole Route to Android Coding Using Kotlinby@rahulchowdhury
608 reads
608 reads

The Wormhole Route to Android Coding Using Kotlin

by Rahul ChowdhuryNovember 30th, 2017
Read on Terminal Reader
Read this story w/o Javascript
tldt arrow

Too Long; Didn't Read

When <a href="http://kotlinlang.org/" target="_blank"><strong>Kotlin</strong></a> was announced as a first class language for Android at <a href="https://www.youtube.com/watch?v=X1RVYt2QKQE" target="_blank">this year’s Google I/O</a>, I made it my top priority to dive into the depths of the language. Although I had heard of Kotlin long time back from one of my friends who happens to be an Android enthusiast as well, I never took the effort to actually learn and use the language for my project, until now.

Companies Mentioned

Mention Thumbnail
Mention Thumbnail
featured image - The Wormhole Route to Android Coding Using Kotlin
Rahul Chowdhury HackerNoon profile picture

Put your Android Development in Nitro Mode

When Kotlin was announced as a first class language for Android at this year’s Google I/O, I made it my top priority to dive into the depths of the language. Although I had heard of Kotlin long time back from one of my friends who happens to be an Android enthusiast as well, I never took the effort to actually learn and use the language for my project, until now.

Kotlin as a language is beautiful. It’s concise, powerful and has a very flat learning curve. Once you start getting used to this language, there’s no looking back. No disrespect for Java, but I don’t think I will use Java again for Android.

Nevertheless, a tool is only as powerful as to the extent of how you use it. If you’re not going to harness the hidden gems in the language, then you might as well not use it. As I have been exploring the language, there have been some aspects of how Kotlin can speed up Android app development that caught my attention, I am going to share them with you so that you can take the wormhole and get home from office by 6.

1. Apply Android Extensions Plugin

The first thing you can do is get rid of all those ugly findViewById() calls, or any framework that you use for injecting your views to your Activity or Fragment or other Views.

JetBrains has bundled an Android extensions plugin with its Kotlin plugin which lets you access views in your Activity, Fragment or View as if it’s just a predefined property. Confused? Just wait till you see the example.

For starters, you need to add this line to your app’s build.gradle.

apply plugin: 'kotlin-android-extensions'

Now your project should be ready to take advantage of Kotlin’s Android Extensions plugin.

How to use it?

It’s dead simple. There’s nothing to setup. No initializations to make. Just refer to your views in your Activity or Fragment or View using the IDs that you declared in the XML layout.

So, let’s say you have declared your view in XML like this,

<android.support.v7.widget.RecyclerView    android:id="@+id/recyclerView"    android:layout_width="match_parent"    android:layout_height="wrap_content"/>

Then, you can access your RecyclerView in your Activity or Fragment or View, in this fashion,

recyclerView.adapter = adapter

That’s it. You don’t need to explicitly resolve the view from the XML or do any other sort of tango. No findViewById(). No ButterKnife. Your views are ready to be referred and used in your Kotlin code.

This, however, will fail to work if your Kotlin class isn’t an Activity or Fragment or View because there isn’t any attached layout to the class to traverse and locate your views. But that doesn’t stop it from casting its charm. If you have an inflated View, then you can access it’s child views using this approach,

view.textView.text = "Hello"view.buttonSubmit.setOnClickListener {    println("Button Clicked!")}

This approach is useful in cases like accessing views inside your RecyclerView’s ViewHolder, where you need to access your views like this,

class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {    fun bindData(newsModel: NewsModel) {        with(newsModel) {            itemView.heading_news.text = heading        }    }}

Note that in the above code snippet, we are referencing the views present inside each row element by using their parent’s reference which is itemView. With this, you can bind pretty much every view in your project without even writing an extra line of code to do all the ceremony. findViewById() was so last year.

What you need to know

Android Studio does all the dirty work of importing classes seamlessly, so you never have to worry about writing out import statements yourself. However, in case the IDE fails to do that, you need to add this import statement wherever you are accessing views directly using the extension,

import kotlinx.android.synthetic.main.your-layout.*

And for the latter case, which is accessing views in classes that are neither an Activity nor a Fragment or a View, you need to add in a teeny tiny bit more information,

import kotlinx.android.synthetic.main.your-layout.view.*

That should be enough to do the job.

2. Get a Helping Hand from Anko

JetBrains, the guys behind Kotlin released a library called Anko which is yet another tool to get the shortcut route to development completion. It includes a number of functions and approaches which will help you cut down your development time and be happy at the same time by writing compact and beautiful code for some of the very common things that we do in an Android app.

To get started, you will need to add a dependency to your build.gradle,

dependencies {    compile "org.jetbrains.anko:anko:0.10.1"}

After you have performed a Gradle Sync, you should be ready to harness the power of Anko in your project.

Anko comprises of several parts to cover a variety of use cases in your project,

  • Anko Commons — for launching Intents, showing Dialog, etc
  • Anko Layout (wiki) — write dynamic layouts without any XML
  • Anko SQLite (wiki) — simplified usage of Android’s SQLite
  • Anko Coroutines (wiki) — helpers for Kotlin’s Coroutine

For the sake of brevity, I will only be talking about the usage of Anko Commons in this article. Let’s dig into it.

Anko Commons offers easier and compact code to perform the most common functions in any Android app. Some of the use cases are,

Launching an Intent

Launching an Intent is probably the most common aspect of navigating from one screen to another in an Android app. This, however, requires a lot of ceremonies to perform especially when it comes to passing data from one activity to another.

For example, if we want to launch a UserDetailsActivity from the MainActivity and pass some user data and make the activity a singleTop activity then there’s a lot to write,

val userActivity = Intent(this, UserDetailsActivity::class.java)userActivity.putExtra("id", 1)userActivity.putExtra("name", "Rahul")userActivity.flags = Intent.FLAG_ACTIVITY_SINGLE_TOPstartActivity(userActivity)

That’s 5 lines of code for a simple task. With Anko, you can boil that down to a one-liner, just like this,

startActivity(intentFor<UserDetailsActivity>("id" to 1, "name" to "Rahul").singleTop())

It’s simple. Meaningful. Doesn’t hurt your fingers anymore.

Showing a Message

Two most common ways of showing a message to the user of your app are by either showing a Toast or a Dialog. Anko injects some goodness serum to both of them.

Showing a Toast is as easy as,

//Normal toast using a hardcoded stringtoast("Hi there!")//Normal toast using a string resourcetoast(R.string.welcome)//Long toastlongToast("Wow, such a duration")

No more forgetting to call the show() function after writing a Toast message.

Dialogs are easy too,

alert(Appcompat, "Hi, I'm Rahul", "Do we know each other?") {    yesButton { toast("Oh…") }    noButton {}}.show()

Well, that wasn’t hard to write. Note, Appcompat is specified here to tell Anko to render the AppCompat version of the dialog. If you don’t want that, you can skip that parameter.

You can get a full overview of the Anko Commons wiki over here.

Things to know

Since Anko is a total package of several parts such as Commons, Layouts, SQLite and Coroutines, the normal package that we added increases your app size and function count by a significant amount. It’s a good practice to include only the required modules and omit the rest to keep your APK slim.

You can add individual dependencies in this fashion, whichever modules you might need for your project,

dependencies {    // Anko Commons    compile "org.jetbrains.anko:anko-commons:0.10.1"

    // Anko Layouts    compile "org.jetbrains.anko:anko-sdk25:0.10.1"    compile "org.jetbrains.anko:anko-appcompat-v7:0.10.1"

    // Coroutine listeners for Anko Layouts    compile "org.jetbrains.anko:anko-sdk25-coroutines:0.10.1"    compile "org.jetbrains.anko:anko-appcompat-v7-couroutines:0.10.1"

    // Anko SQLite    compile "org.jetbrains.anko:anko-sqlite:0.10.1"}

3. Write Extension Functions

One of the best things about Kotlin is the ability to write extension functions and properties. Considering how screwed up some Android APIs are, this is a boon for all Android app developers. Don’t freak out if my words aren’t making any sense to you, you will get it in a minute, but before diving into how to write extension functions in Kotlin, let’s have a short intro on what they are.

What are extension functions?

Kotlin provides an ability to developers to add functions to a project or platform (i.e., SDK) class without actually extending the class or modifying it in any conventional way.

Let’s clear it out with an example, suppose we have a Kotlin class like this,

class StandardClass {    fun doSomething() {        //Do something here        println("Maybe print something")    }}

We can now inject a function to this class which will behave like a regular function inside the class and has access to all the properties and functions present in the class without even extending it. How? This is how.

fun StandardClass.doSomethingMore() {    //Do something more here    println("Maybe print something new and extra")}

That’s all, and do note that this function can be defined anywhere, even as a top level function in a regular .kt file. The syntax or structure of defining such an extension function is as follows,

fun receiver-class-name.function-name() {    //Body of the function goes here}

How does this help?

Well, all this looks very fancy, but where’s do these funky features actually come in handy when it comes to Android app development? The answer is simple. It’s your standard utilities class given a whole new dimension with the power to add missing utilities to platform APIs.

Consider this case for an example. Inflating a view and adding it to a ViewGroup is a tedious task. For starters, you will have to get an inflater like this,

val inflater = LayoutInflater.from(context)

Then, you will have to inflate the layout and add it to the parent ViewGroup like this,

inflater.inflate(R.layout.view_layout, parent, true)

And you will have to do this every time you need to inflate a layout, which happens a lot of time in an Android project. So how do we make it better? We create an extension function of it.

fun ViewGroup.inflate(layoutId: Int, attachToRoot: Boolean = false): View {    return LayoutInflater.from(context).inflate(layoutId, this, attachToRoot)}

You can now inflate any layout by calling the inflate() function on any ViewGroup object throughout your project, like this,

view.inflate(R.layout.view_layout)

A thing to note in the function definition above is that we didn’t take the context as a parameter but are still able to resolve and use it. This is because since we added an extension function to the class ViewGroup, we now have access to all this properties and functions within the function block. Context being one of the defined properties in the class we can use it without any extra effort to retrieve it.

Not convinced yet? Here’s another example to change your mind,

fun SharedPreferences.save(function: SharedPreferences.Editor.() -> Unit) {    val editor = edit()    editor.function()    editor.apply()}

What this function does is extend the SharedPreferences class in Android to easily save data in the preferences without performing all the rituals such as getting a SharedPreferences.Editor object from the preferences object and remembering to call apply() or commit() after putting all the data.

Using this function is super easy,

val sharedPref = PreferenceManager.getDefaultSharedPreferences(applicationContext)sharedPref.save {    putString("name", "Rahul")    putBoolean("isLoggedIn", true)}

That’s was all to save some data to your app’s shared preferences.

Although it might take some time initially to set up all the extension functions, once you do, your productivity will take a leap and you will be able to code much faster. Best thing? You can share your extension functions across projects and reuse them as much as you want.

With extension functions, you can extend the time you have for the other things in your life.

4. Make Data Classes Work for You

Kotlin introduced Data Classes to simplify the creation and maintenance of model classes. Long gone are the days when you needed to write enormous boilerplate code just to create a model class.

Google tried to solve this problem with AutoValue. Some others tried to solve it by creating plugins for the IDE to generate all that code for you, but having the feature built-in the language is a treat. Nothing to include. No third-party plugins to install.

What’s so special?

Kotlin Data Classes generate the following things automatically for you under the hood keeping your code clean and your fingers relaxed –

  • equals() and hashCode() functions for model comparison
  • a formatted toString() function to output the contents in a readable fashion
  • componentN() functions which are used to access the properties in the class
  • copy() function to copy properties from one object to another easily

All these are generated in a stealth mode which means you don’t get to see any of these functions on your Kotlin code keeping your data class clean and concise.

How to declare a class as a Data Class?

Just add the keyword data in front of your class definition. Nothing more to do here. For example, you can define a UserModel class like this,

data class UserModel(val name: String, val age: Int, var isOnline: Boolean)

Yes, you can define a whole model class in just a single line. This can’t get easier than this.

The best part of this is if we want to introduce a new property to the UserModel, it would be a change of just a few characters. Let’s add a property to hold the date of birth of the user.

data class UserModel(val name: String, val age: Int, var isOnline: Boolean, val dateOfBirth: Date)

That’s it. I have just added a new property in the primary constructor definition. Kotlin will take care of the rest. No more adding new getter and setter or updating the toString() method.

Usage in a regular Android app

Almost every Android app holds data in a model. Be it user data or something else. Consider an app which connects to a backend API using Retrofit and stores the response in a model class defined like this,

data class UserApiResponse(@SerializedName("user_name") var   userName: String,                           @SerializedName("age") var age: Int)

It’s naive to consider that once the model is defined it won’t change. It can and will change (not trying to look cool by applying Murphy’s law here).

Doesn’t matter if your app is local or connects to a backend API to get data, your local database schema or API response format is very much susceptible to change.

What happens when it does change? You take a trip down your project structure, find the model class and make the necessary changes.

Had it been the old-school way of updating your model classes, you would have to spend a good minute or two or boring task to add the field, create getters and setters, and update the toString() function as well.

Thankfully, we don’t do that sort of manual labour anymore, remember? Kotlin takes care of all that for us. Time saved.

Android app development is a time-consuming job. Kotlin is on a mission to make it a pleasant experience and speed up the process along the way. Make sure you use as many tricks as possible to take full advantage on this new language.

See you next time, in another tutorial or general knowledge talk. Share this article if you liked it.

Clap. Clap. Clap. Helps me get motivated to write more of this stuff for you.