Kotlin and Android Development

Kittinun Vantasin

Speaker

github.com/kittinunf

@kittinunf

Kotlin ... why?

Stuck on old Java (6-ish)

  • No javax.time

  • No streams API

  • No lambdas, method refs

ThreeTenAndroidBP

Standalone backport / RxJava

Retrolambda

Kotlin ... why?

Kotlin ... why?

Inherent Java language restrictions

  • Cannot add methods on platform types

  • Problem with null

  • Mutability is everywhere

  • Force to evolve everything around Object

Kotlin ... why?

Android restrictions

  • Large inheritance tree

  • Nullability usage

  • API ceremony

Kotlin

Statically typed programming language
for the JVM, Android and the browser

100% interoperable with Java™

Kotlin - Crash course

Null safety Enum class Immutability
Type Inference Properties & Fields Data class
Lambda Extension Functions High order functions
Type-safe builder Collection APIs Kotlin-Java Interoperable

Null Safety

 
 val nullableString: String? = null

 //safe call
 nullableString?.length

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


 fun doSomething(s: String) {}

 //compile error
 doSomething(nullableString) 

 fun doAnotherThing(s: String?) {}

 //compile
 doAnotherThing(nullabeString) {}

Type inference

 val i: Int = 10

 val j = 10 //type is infered

 fun add(x: Int, y: Int): Int { 
    return x + y
 }

 fun add1(x: Int, y: Int) = x + y
 
 
 val string: String? = "Hello"

 println(string?.length) //need to use safe call(?:) operator
 
 string?.let {
   println(string.length) //?: is no longer needed
 } 

 if (string != null) {
   println(string.length) //here ?: is not needed
 }

Extension Functions

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

  31.fib() //print 1346269

  

Lambda

    
    val powOfTwo = { i: Int -> i * i } //type = (Int, Int) -> Int
    
    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"

What does this mean to Android Developer?

Kotlin ❤️ Android

In the nutshell

Java

Kotlin

javac

kotlinc

Bytecode

Android

Kotlin Android Extension

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        tools:text="John Appleseed"
     />
    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"
      }
    }

SAM Conversion

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

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

        button.setOnClickListener { 
          println("do something useful")
        }
      }
    }

    //compiler shows you
    public fun setOnClickListener(
       listener: ((v: View) -> Unit)): Unit

Extension....


  // get all the children in ViewGroup
  fun ViewGroup.children(): List<View> = 
    (0..childCount - 1).map { getChildAt(it) }

  // is View visible
  val View.isVisible: Boolean = visibility == View.VISIBLE

  // get locationManager in Context
  val Context.locationManager: LocationManager
    get() = getSystemService(Context.LOCATION_SERVICE) as LocationManager
fun TextView.textChangedListener(init: _TextWatcher.() -> Unit) {
    val listener = _TextWatcher()
    listener.init()
    addTextChangedListener(listener)
}

class _TextWatcher : android.text.TextWatcher {
    private var _beforeTextChanged: ((CharSequence?, Int, Int, Int) -> Unit)? = null
    private var _onTextChanged: ((CharSequence?, Int, Int, Int) -> Unit)? = null
    private var _afterTextChanged: ((android.text.Editable?) -> Unit)? = null

    override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
        _beforeTextChanged?.invoke(s, start, count, after)
    }

    fun beforeTextChanged(listener: (CharSequence?, Int, Int, Int) -> Unit) {
        _beforeTextChanged = listener
    }

    override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
        _onTextChanged?.invoke(s, start, before, count)
    }

    fun onTextChanged(listener: (CharSequence?, Int, Int, Int) -> Unit) {
        _onTextChanged = listener
    }

    override fun afterTextChanged(s: android.text.Editable?) {
        _afterTextChanged?.invoke(s)
    }

    fun afterTextChanged(listener: (android.text.Editable?) -> Unit) {
        _afterTextChanged = listener
    }
}
  class MyAwesomeActivity : Activity() {
    fun onCreate() {
      super.onCreate()


      textView.textChangedListener {
        onTextChanged {
          Log.d("onTextChanged", it.toString())
        }
      }

    }
  }

Supercharged API


  inline fun SharedPreferences.edit(
    build: SharedPreference.Editor.() -> Unit) {
    val editor = edit()
    editor.build()
    editor.apply()
  }
  
  fun SharedPreferences.put(p: Pair<String, String>) {
    val (first, second) = p
    putString(first, second)
  }

  //usage
  pref.edit {
    put("username" to "foo")
    put("userId" to "1234")
    remove("bar")
  }

Convinced ?

How Cookpad Team use Kotlin

Resources

Website and Documentation

https://kotlinlang.org/

Online Compiler

http://try.kotlinlang.org/

Hand-on learning

https://github.com/Kotlin/kotlin-koans

Q & A

Tell us what you think

https://goo.gl/GU8vK2

Made with Slides.com