All you need to start creating Android app in Kotlin.

Kotlin Syntax

print("Amit Shekhar")
println("Amit Shekhar")

Constants and Variables

var name = "Amit Shekhar"
val name = "Amit Shekhar"

Assigning the null value

var otherName : String?
otherName = null

Verify if value is null

text?.let {
    val length = text.length
}
// or simply
val length = text?.length

Concatenation of strings

var firstName = "Amit"
var lastName = "Shekhar"
var message = "My name is: $firstName $lastName"

New line in string

val text = """
        |First Line
        |Second Line
        |Third Line
        """.trimMargin()

Ternary Operations

val text = if (x > 5)
              "x > 5"
           else "x <= 5"

val message: String? = null
log(message ?: "")

Bitwise Operators

val andResult  = a and b
val orResult   = a or b
val xorResult  = a xor b
val rightShift = a shr 2
val leftShift  = a shl 2
val unsignedRightShift = a ushr 2

Check the type and casting

if (object is Car) {
}
var car = object as Car

// if object is null
var car = object as? Car // var car = object as Car?

Check the type and casting (implicit)

if (object is Car) {
   var car = object // smart casting
}

// if object is null
if (object is Car?) {
   var car = object // smart casting, car will be null
}

Multiple conditions

if (score in 0..300) { }

Multiple Conditions (Switch case)

var score = // some score
var grade = when (score) {
	9, 10 -> "Excellent"
	in 6..8 -> "Good"
	4, 5 -> "OK"
	in 1..3 -> "Fail"
	else -> "Fail"
}

For-loops

for (i in 1..10) { }

for (i in 1 until 10) { }

for (i in 10 downTo 0) { }

for (i in 1..10 step 2) { }

for (i in 10 downTo 0 step 2) { }

for (item in collection) { }

for ((key, value) in map) { }

Collections

val listOfNumber = listOf(1, 2, 3, 4)
val keyValue = mapOf(1 to "Amit",
                     2 to "Ali",
                     3 to "Mindorks")

for each

cars.forEach {
    println(it.speed)
}

cars.filter { it.speed > 100 }
      .forEach { println(it.speed)}

// kotlin 1.1+
cars.stream().filter { it.speed > 100 }.forEach { println(it.speed)}
cars.parallelStream().filter { it.speed > 100 }.forEach { println(it.speed)}

Splitting arrays

val (param, value) = "param=car".split("=")

Defining methods

fun doSomething() {
   // logic here
}

Variable number of arguments

fun doSomething(vararg numbers: Int) {
   // logic here
}

Defining methods with return

fun getScore(): Int {
   // logic here
   return score
}

// as a single-expression function

fun getScore(): Int = score

// even simpler (type will be determined automatically)

fun getScore() = score // return-type is Int

Returning result of an operation

fun getScore(value: Int): Int {
   // logic here
   return 2 * value
}

// as a single-expression function
fun getScore(value: Int): Int = 2 * value

// even simpler (type will be determined automatically)

fun getScore(value: Int) = 2 * value // return-type is int

Constructors

class Utils private constructor() {

    companion object {

        fun getScore(value: Int): Int {
            return 2 * value
        }

    }
}

// another way

object Utils {

    fun getScore(value: Int): Int {
        return 2 * value
    }

}

Getters and Setters

data class Developer(var name: String, var age: Int)

Cloning or copying

data class Developer(var name: String, var age: Int)

// cloning or copying
val dev = Developer("Mindorks", 30)
val dev2 = dev.copy()
// in case you only want to copy selected properties
val dev2 = dev.copy(age = 25)

Class methods

fun Int.triple(): Int {
  return this * 3
}

var result = 3.triple()

Defining uninitialized objects

internal lateinit var person: Person

enum

enum class Direction constructor(direction: Int) {
    NORTH(1),
    SOUTH(2),
    WEST(3),
    EAST(4);

    var direction: Int = 0
        private set

    init {
        this.direction = direction
    }
}

Sorting List

val profile = loadProfiles(context)
profile.sortedWith(Comparator({ profile1, profile2 ->
    if (profile1.age > profile2.age) return@Comparator 1
    if (profile1.age < profile2.age) return@Comparator -1
    return@Comparator 0
}))

Anonymous Class

val task = object : AsyncTask<Void, Void, Profile>() {
    override fun doInBackground(vararg voids: Void): Profile? {
        // fetch profile from API or DB
        return null
    }

    override fun onPreExecute() {
        super.onPreExecute()
        // do something
    }
}

Initialization block

class User {
    init { // Initialization block
        println("Init block")
    }
}

Kotlin Code Snippets

coroutine

package com.abanoubhanna.coroutine

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.coroutines.*
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.Dispatchers.Main

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        button.setOnClickListener {
            setNewText("Click!")

            CoroutineScope(IO).launch {
                fakeApiRequest()
            }
        }
        
    }

    private fun setNewText(input: String){
        val newText = text.text.toString() + "\n$input"
        text.text = newText
    }
    private suspend fun setTextOnMainThread(input: String) {
        withContext (Main) {
            setNewText(input)
        }
    }

    private suspend fun fakeApiRequest() {
        logThread("fakeApiRequest")

        val result1 = getResult1FromApi() // wait until job is done

        if ( result1.equals("Result #1")) {

            setTextOnMainThread("Got $result1")

            val result2 = getResult2FromApi() // wait until job is done

            if (result2.equals("Result #2")) {
                setTextOnMainThread("Got $result2")
            } else {
                setTextOnMainThread("Couldn't get Result #2")
            }
        } else {
            setTextOnMainThread("Couldn't get Result #1")
        }
    }


    private suspend fun getResult1FromApi(): String {
        logThread("getResult1FromApi")
        delay(1000) // Does not block thread. Just suspends the coroutine inside the thread
        return "Result #1"
    }

    private suspend fun getResult2FromApi(): String {
        logThread("getResult2FromApi")
        delay(1000)
        return "Result #2"
    }

    private fun logThread(methodName: String){
        println("debug: ${methodName}: ${Thread.currentThread().name}")
    }
}

Kotlin Filter

val numbers = listOf(1, -2, 3, -4, 5, -6)            // 1
val positives = numbers.filter { x -> x > 0 }    // 2
val negatives = numbers.filter { it < 0 }         // 3

Finally

I will update this Kotlin documentation/reference monthly. Things to add later: lateinit vs lazy, apply vs with, Data Class, Destructuring Declarations, Extension Functions, Sealed Classes, Understanding Higher-Order Functions and Lambdas in Kotlin, Understanding inline, noinline, and crossinline in Kotlin, Mastering Kotlin Coroutines In Android – Step By Step Guide