The Road to Kotlintown

If you enjoy talks from 360 AnDev, please support the conference via Patreon!

In this talk, we will cover how you can get started with Kotlin. We will cover some best practices and things to avoid.

Introduction

My name is Christina Lee and I’m an Android developer at Pinterest. I’m Huyen Tue Dao and I’m an Android developer at Trello. We will cover Kotlin for people without Kotlin experience by live coding a sample app with common technologies such as Dagger and Retrofit.

Converting to Kotlin

First, convert a Java file to Kotlin file. If I examine the Java version of the code, I see that it was public abstract class. In Kotlin, you would not need to specify public because it is the default.

Kotloin allows you to place things at a top level of a file. A note on access modifiers:

  • private - means that the signature can only be seen in that particular class.
  • internal - anybody in the module that can see this class, can also see all internal members of the class.
  • protected - it’s private, but some classes can also see this field.

Get more development news like this

In Kotlin, abstract is unchanged. If that abstract class has members, they need to be implemented.

Extension (inheritance) is not noted with a “:”.

Primary and Secondary Constructors

Suppose an Animal class has legs. The following would be an example of a primary constructor.


class Animal(legs: Int) {
  constructor(legs: Int)
  
  init {
  
  }
}

In an instance that an animal may also have fur, I can use a secondary constructor:

class Animal(legs: Int) {
  constructor(legs: Int, furType: String) : this (legs)
  
  init {
  
  }
}

Here, I will pass the secondary information to the primary constructor.

Classes

Scoping

class Animal(legs: Int) {

  var legsPlusOne = legs + 1
  init {
    legs // in scope
  }
}

In the above class, legs, when assigning to the variable legsPlusOne and in the init block, is in scope.

Note that if you write a function lower in the class, legsPlusOne is in scope, but legs is not.

class Animal(legs: Int) {

  var legsPlusOne = legs + 1
  init {
    legs // in scope
  }
  
  fun someFun() {
    legs // not in scope
    legsPlusOne // is in scope
  }
}

Nullability

Kotlin has the idea of a nullability type. It can be there, or it can also not be there and it can be null. If I remove or add a ?, it determines whether I need to check for null, before working with the variable.

private lateinit var unbinder: Unbinder

If you ever think that you’re smarter than a compiler, you have this great opportunity to prove it by using the keyword lateinit. Using this keyword tells the compiler, “I know that it looks like this isn’t initialized, but I can guarantee that before I use it, it will be.” But, if you are wrong, it will crash.

Handling Nullability

In onCreateView, all of the parameters are marked nullable.


override fun onCreateView(inflater: LayoutInflator?,...) 

Anytime you have something that’s marked nullable, you have to handle both cases, which results in a different branch and adds code complexity. You may want to remove question marks to simplify your code, but in some cases, it would cause it to no longer compile, as the signature no longer matches.

A bad null handling policy is this:


inflator!!.context

Here, if the inflator is null, it will throw a NullPointerException if it is in fact null.

A better one is this:


inflator?.context

This second one is better because it gives you a chance to avoid a NullPointerException.

Lambda

Lambda is a function literal. It allows you to define a function as an expression that you can pass to other methods. We have a retry button, with a familiar setOnClickListener, and rather than instantiating and passing a ClickListener, we’re passing it a lambda, which contains all of our click button behaviors.

A Kotlin Lambda will have braces. First, it will contain a list of parameters that go to your function/lambda. As we are in Kotlin world, the way that the parameters are defined are name first, and then type second. And then you’ll see this right arrow. And then you’ll have the body of your function, the actual behaviors.


retryButton.setOnClickListener { v ->
  v.visibility = View.INVISIBLE
  load()
}

When you have a lambda that has a single parameter, you can ask Kotlin to implicitly declare it for you.

Companion object

Kotlin does not have static variables. Instead, Kotlin has a companion object, which allows you to do static variables. Within the object, you can declare properties and methods that you can call in static-like ways.


companion object {
  private val SPAN_COUNT = 2
  
  private val PERMISSIONS_REQUEST_INTERNET = 100
}

If I wanted to call something in my companion object in other Kotlin code, I might write UnsplashListFragment.SPAN_COUNT, to achieve a static-like behavior in our Kotlin.

Boxed, Unboxed Arrays

In Kotlin, there are many types of arrays - e.g. boxed arrays.

The difference between boxed and unboxed arrays is straightforward. Boxed arrays are arrays with boxed types. Unboxed arrays are arrays of primitive types.

A Caution

Converting Java to Kotlin will result in code that is syntactically correct, but will result in it being more difficult to read.

For example, here, I have a network request with a success and error callback. They’re not lined up, and it almost looks like they’re in two different places.

It’s disjointed and hard to understand.

Next Up: Kotlin in Depth #4: Advancing Android Development with Kotlin

General link arrow white
`

Huyen Tue Dao

Huyen Tue Dao is an Android developer and Google Developer Expert, currently working on the Trello Android app at Atlasssian. She is also co-creator of the “Android Dialogs” YouTube channel. Huyen lives in Denver, CO though is often found in the DC Metro area. When she is not up late programming, she is often found up late gaming (video, board, card, anything).

Christina Lee

Christina is currently the Android lead at Highlight. In addition to trying to convince the world to use Kotlin on a daily basis, she also enjoys building beautiful UIs, extolling the virtues of Rx, and reading well documented APIs.