Introduction to Kotlin for Android Development

Kittinun Vantasin

Speaker

github.com/kittinunf

Taskworld

Agenda

Kotlin 101

Kotlin in Android Development

Q&A

Kotlin

Statically typed language for JVM, Android, and the browser

Created by Jetbrains back in 2010

Open sourced, hit 1.0 released in Feb, 2016 

Seamlessly integrate with IntelliJ platform - also Android Studio

Kotlin in 2 mins

Why Kotlin?

Java suffers with backwards & compatibility

Development of Java itself is slow

Java 6 12/2006

Java 7 7/2011

Java 8 3/2014

Java 9  ~3/2017

Flawed Type system 

 
          
          object instanceof T; 
          T t = (T) object;
         T[] array = new T[1];

Low surface area to explore, easier to grasp

Why Kotlin?

Simple, expressive, versatile, interoperable - Pick 4

Compile down to bytecode Java 6, desirable for Android

Safe & Fun

 fun main(args: Array<String>) {
     val name = args.getOrNull(0) ?: "No name"
     println("Hello $name to Kotlin Konference!")
 }

Kotlin - The BIG 12

Null safety Enum class Immutability
Type inference & Cast Properties & Fields Data class
Lambda Extension Functions High order function
Type safe builder Collection API Kotlin-Java interoperable

NULL

A better way to deal with NPEs

Java Kotlin
Nullable T T?
Non-null T T

Safe call or handle manually, let to express intent of unwrapping

 //cannot compile
 val name: String = null
 
 //compile
 val nullableName: String? = null

 //compile
 val nonNullName = "Kittinun" // type is String

 fun doSomething(name: String) {
     ...
 }
 
 //cannot compile
 doSomething(null)

 val anotherNullableString: String? = "nullable"

 //compile
 doSomething(nonNullName)
 
 val nullableString: String? = null

 //safe call
 nullableString?.length

 //NPE lovers
 nullableString!!.length //throw NPE

 //unwrapping
 val anotherNullableString: String? = "Kittinunf"
 anotherNullableString?.let {
     //safe as nullable won't enter this block
     val length = anotherNullableString.length
     println(length) //print 9
 }

 if (anotherNullableString != null) {
     //also safe
     println(anotherNullableString.length) //print 9
 }

Enum Class

Type safe enum

Contains value that initialized at construction

 enum class Orientation(val value: String) {
    HORIZONTAL("H") {
        override fun intRepresentation() = 1
    },

    VERTICAL("V") {
        override fun intRepresentation() = 2
    },
    
    REVERSE_HORIZONTAL("R_H") {
        override fun intRepresentation() = -1
    };
    
    abstract fun intRepresentation(): Int
 }
 val h = Orientation.HORIZONTAL
 val rh = Orientation.REVERSE_HORIZONTAL

 println(h.value) //print "H"
 println(rh.intRepresentation()) //print -1

Safe & easily use across code base

Immutability

Built-in support for mutable & immutable properties/variables

Design with Mutable/Immutable interface 

    val i: Int = 10
    var mi: Int = 5
    
    //cannot compile, i cannot be re-assigned
    i = 1000 
    mi = 1000
    
    //cannot compile, i is immutable and cannot be re-assigned
    i += 4
    
    val arr: List<Int> = listOf(1,2,3,4,5)
    
    //cannot compile, add is unresolved reference
    arr.add(8)

    val marr: MutableList<Int> = mutableListOf(1,2,3,4,5)
    marr.add(8) //becomes 1,2,3,4,5,8

Type Infer & Cast

No need to explicitly declare type, compiler works that out for you

Smart Cast makes your life much better

    val j = 10
    //val j: Int = 10

    //be explicit as needed
    val jj: Int? = 20
    
    val i = powerOfTwo(6)

    fun powerOfTwo(i: Int) = i * i

    jj?.let {
        //smart cast to Int
        println(jj.toString())
    }
    
    //type is Int?
    jj?.toString()

    val e: Any = "Hello"
    if (e is String) {
        //smart cast to String
        println(e.length) //print 6
    }

Properties & Fields

Properties in Kotlin is rich in features

Handy delegated properties

    enum class Color {
        BLUE,
        RED,
        GREEN,
        WHITE;
    }

    class Car(
        val make: String,
        val year: Int,
        var color: Color,
        val vinNumber: String,
        var secondHanded: Boolean
    )

    val jazz = Car("Honda", 2014, Color.WHITE, "aa76efc1", false)
    
    //cannot compile as make is immutable
    jazz.make = "Toyota" 
    jazz.bought()

    jazz.secondHanded = true //compile
    class Controller {
    
        val computed: String 
            get() { return "hello" }
        
        var counter = 0 
            set(value) {
                if (value >= 0) field = value
            }
        
        lateinit var toBeInit: Foo
    
    }
    
    val c = Controller()
    c.computed //return "hello"
    
    c.value = 10 //value = 10
    c.value = -1 //value is not set, value is still 10

    c.toBeInit //throw exception uninitialized
    
    c.toBeInit = Foo()
 
    c.toBeInit.doSomethingAwesome() 
    class Foo {
    
        val lazyValue by lazy {
            println("lazy will be created once")
            Bar()
        }
    
        var observedValue by Delegates.observable("not set") { 
            meta, oldValue, newValue -> 
            println("From \"$oldValue\" To \"$newValue\"")
        }
    
    }

    val f = Foo()
    f.observedValue = "hello" //print - From "not set" To "hello"
    f.observedValue = "world" //print - From "hello" To "world"
    

Data class

Short hand notation for verbose counterpart in Java


    class Device(
        val type = "Unknown"
        val platform = "Android"
    )

    println(Device()) //print Device@63adf08f


    data class DeviceData(
        val type = "Unknown"
        val platform = "Android"
    )
    
    val d1 = DeviceData()
    val d2 = DeviceData()
    println(d1) //print DeviceData(type=Unknown, platform=Android)

    println(DeviceData("Samsung")) //print DeviceData(type=Samsung, platform=Android)

    println(d1 == d2) //print true!
    
    val (type, platform) = d1 //type="Unknown", platform="Android"

equals()/hashCode() pair,

toString() of the form "<Class>(c1=..., c2=...)",

componentN() functions corresponding to the properties in their order of declaration,

copy() function

Lambda

Lambda as a first class type



    val powOfTwo = { i: Int -> i * i }
    
    println(powOfTwo(5)) //print 25
    
    class Foo {
    
        var value: String by Delegates.observable("") { meta, oldValue, newValue ->
            updateListener?.invoke(newValue)
        }
        
        var updateListener: ((String) -> Unit)? = null
    
    }

    val f = Foo()
    
    f.value = "v1"
    f.updateListener = ::println
    f.value = "v2"  //print "v2"
    f.value = "v3"  //print "v3"

Lambda is useful to substitute of usage of interface

Extension Functions

You can extend functionality of existing class without interitance



    fun Int.fib(): Int {
        var last = 0
        var prev = 1
    	
        var result = 0
        for (i in 2..this) {
            result = last + prev
            last = prev
            prev = result
        }
        
        return if (this == 1) 1 else result
    }

    31.fib() //print 1346269

Extremely handy for class that you do not own

High Order Functions

Function as first class citizen


    fun Int.fib2(): Int {
        var (last, prev) = 0 to 1
        
        val s = generateSequence(2) { 
            val v = it + 1 
            if (v > this) null else v
        }
        
        val result = s.fold((last to prev)) { agg, item -> 
            val (l, p) = agg
            p to l + p              
        }.second
        
        return if (this == 1) 1 else result
    }

    31.fib2() //print 1346269

    (0..10).filter { it > 5 } // print 6,7,8,9,10
    
    //print 36,49,64,81,100
    (0..10).filter { it > 5 }.map { it * it } 
    
    //print sum(36,49,64,81,100) 330
    (0..10).filter { it > 5 }.map { it * it }.reduce(Int::plus) 

Support functional programming concepts

Type safe builder

Builder pattern for Free


    data class Bar(val i: Int)

    class Complicate {
        private val children = mutableListOf<Bar>()
        
        companion object {
            fun build(init: Complicate.() -> Unit): F {
                val c = Complicate()
                c.init()
                return c
            }
        }
        
        fun add(b: Bar) {
            children.add(b)
        }
    }

    val c = Complicate.build {
        add(Bar(1))
        add(Bar(2))
        add(Bar(3))
    } //c.children [Bar(1), Bar(2), Bar(3)]

DSL for class

Collection API

Rich collection API covers almost every use case


    val a = (1..10) + (1..10)
    
    a.all { it > 0 }                            a.subtract(5..10)
    
    a.any { it % 2 == 0 }                       a.sortedWith { .... } 

    a.average()                                 a.sum()

    a.distinct()                                a.take(3)

    a.dropWhile { it < 5 }                      a.toList()/a.toArrayList()

    a.filterNot { it > 0 }                      a.toSet()/a.toHashSet()

    a.groupBy { if (it < 3) "<3" else ">3" }    a.toCollection(MyAwesomeCollection())
    
    a.intersect(2..4)                           a.toLinkList()

    a.joinToString("-")                         a.toMap({ if (it % 2 == 0) "even" else "odd" }, 
                                                        { it.toString })

    a.max(), a.min()                            a.map { it to it.toString() }.unzip()

    a.none { it < 1 }                           a.withIndex()

    a.reversed()                                a.union(10..20)

    a.sortedBy { it % 3 == 0 }                  a.zip(10..20) 
    

Versatility

Backend ? - Yes, ktor (https://github.com/Kotlin/ktor)

Frontend ? - Kotlin supports Javascript, see for youself at web-demo (http://try.kotlinlang.org/#/Examples/Canvas/Fancy%20lines/Fancy%20lines.kt)

Desktop ? - It is!, take a look at TornadoFx (https://github.com/edvin/tornadofx)

You should be convinced by NOW!

If not, go see it yourself https://kotlinlang.org/

Try online at http://try.kotlinlang.org/

Dig deeper - Android

Expressiveness makes Android development pleasant

Extension function brings Android dev to the whole new level

Interop with Java makes you feel "at home"

If you know Java, Kotlin is half way there

Kotlin ❤️ Android

Then, you are 3 fingers away from Kotlin?

Cmd + Shift + a

Getting started by install Kotlin IDE plugin

In the nutshell

Java

Kotlin

javac

kotlinc

bytecode

Android

Dalvik

ART

Kotlin Android Extension

findViewById()

    import kotlinx.android.synthetic.main.activity_main.*

    class MyAwesomeActivity : Activity() {
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_my_awesome)

            textView.text = "Hello Kotlin for Android"
        }
    }
    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        tools:text="John Appleseed"
     />

 Extension function

  class MyAwesomeActivity : Activity() {
      fun handleSuccess() {
          toast("Success!")

          //long
          toast("Successsssss!", Toast.LENGTH_LONG)

          logD("hello")
      }
  }
    
  fun Context.toast(msg: String, 
                  length: Int = Toast.LENGTH_SHORT) {
      Toast.makeText(this, msg, length).show()
  }

  fun logD(msg: Any, tag: String = "LOG") {
      Log.d(tag, msg.toString())
  }

 Extension function


  fun Realm.transaction(call: (Realm) -> Unit) {
      beginTransaction()
      call(this)
      commitTransaction()
  }

  open class Dog(open var name: String,
                 open var age: Int,
                 open var breed: String) : RealmObject
  
  val dog = Dog("Albert", 3, "Shizu")
  
  val realm = Realm.getDefaultInstance()

  realm.transaction {
    it.copyToRealm(dog)
  }

Nice API to work with

    val url = URL("http://www.google.com")
    val executor = Executors.newScheduledThreadPool(4)
 
    override fun onCreate(savedInstanceState: Bundle?) {
        dispatch(executor) {
            url.readText()
        }
    }

    class Async<T>(val weakRef: WeakReference<T>)

    fun <T> T.dispatch(executorService: ExecutorService, 
                       block: Async<T>.() -> Unit)
                        : Future<Unit> {
        val a = Async(WeakReference(this))
        return executorService.submit<Unit> { a.block() }
    }

Nice API to work with


    operator fun ViewGroup.get(index: Int): View 
                = getChildAt(index)

    val container = getContainer()

    val childAtTwo = container[2]


    override fun onBindViewHolder(holder: ViewHolder, index: Int) {
        val car = items[index]
        with(car) {
            Glide.with(holder.itemView.context).load(coverPhotoUrl)
            itemView.descTextView.text = desc
            itemView.setOnClickListener { 
                toast("ItemClick")
            }
        }
    }

Handy stuffs


    //singleton
    object GsonManager {
        fun register() {
        }

        fun addDateTimeStampFormat(format: String) {
        }
    }
    
    class MyAwesomeApplication : Application() {
        override fun onCreate() {
            GsonManager.register(...)
        }
    }
    
    //delegates
    class MyAwesomeListActivity : Activity() {
        private var items: List<Model> by Delegates.observable(listOf()) { 
            meta, oldValue, newValue ->
            adapter.notifyDataSetChanged()
        }

        val adapter = MyAwesomeAdapter()

        fun onSuccess(models: List<Model>) {
            items = models
        }
    }

Handy stuffs


    val name: String? = "Andy"
    val address: String? = null

    name?.let {
        //name has been smart-casted to String
        println(name.length) //print 4
    }
    
    address?.let {
        //this block is skipped due to safe call (?.)
    }
    
    data class Person(name: String, age: Int, address: String)
    
    fun constructPerson(name: String, age: Int, address: String): Person {
        return Person().apply {
            name = "Wipoo"
            age = 24
            address = "68 Soi Phahonyothin 6"
        }
    }

    //use makes closable operation easy to reason, and safe
    Files.newOutputStream(path).use {
       it.write("foo")
       it.write("bar")
    }

    //resource is closed properly
    

If these do not make you wanna use Kotlin, I don't know what will 

Drawbacks

Small community

Not stable with annotation processing 

Not plays well with Mockito 

Debugger in lambda can be tricky

Need a kickass presentation to win teammates over

Things we've shared

Utils: taskworld/KxAndroid

Networking: kittinunf/Fuel

Functional patterns: kittinunf/Result

Reactive Components: kittinunf/ReactiveAndroid

SharedPreference: verachadw/Kreference

Cache: kittinunf/Fuse

Q & A

Introduction to Kotlin for Android Development

By Kittinun Vantasin

Introduction to Kotlin for Android Development

Thailand Developer Konference #1

  • 1,606