Upgrade to Pro — share decks privately, control downloads, hide ads and more …

First few months with Kotlin - Introduction through android examples

First few months with Kotlin - Introduction through android examples

Kotlin introduction through android examples. First Kotlin meetup held in Serbia in organization of Kotlin User Group Serbia.

Nebojša Vukšić

February 28, 2017
Tweet

More Decks by Nebojša Vukšić

Other Decks in Programming

Transcript

  1. What is Kotlin? • statically-typed object oriented programming language •

    targeting JVM, Android and JavaScript • fully interoperable with Java • third party library • has excellent IDE support
  2. Kotlin history • developed by JetBrains • unveiled to public

    in 2011.(development started in 2012.) • 1.0 first stable version (February 2016.) • current version 1.1 RC
  3. Problems that we have: Why do we need Kotlin? •

    Java ◦ is too verbose ◦ burden of previous versions ◦ Null Pointer Exception issues ◦ util “hell” • Android ◦ we need inheritance for almost everything ◦ api ceremony ◦ nullability ◦ lack of Java 8 features (lambdas, stream api, method reference...)
  4. Variables val avenger: String = “Tony Stark” //constants avenger =

    “Ultron” // compile error var age : Int = 18 //variable age = 20 // compiles since age is mutable var number = 20 // Int type is inferred
  5. text.length // compiler error var text: String? = null //

    This can be null or not-null Nullability var name: String = null // compile error text?.length // compiles ⇔ if ( text != null) { text.length // smart casted to not-nullable type } name.length // this is ok since type is not nullable
  6. Nullability val s: String? = "This can be null or

    not-null" val length = s!!.length Making NPE explicit
  7. Nullability val s: String? = "This can be null or

    not-null" val length = s!!.length Making NPE explicit
  8. Functions fun add(a: Int, b: Int): Int { return a

    + b } Calling functions: add(1, 3) log(1, “Num is”) //“Num is 1” fun log(num: Int, msg: String): Unit { println(“$msg $num”) }
  9. Functions fun add(a: Int, b: Int): Int = a +

    b fun log(num: Int, msg: String): Unit = println(“$msg $num”) Calling functions: add(1, 3) log(1, “Num is”) //“Num is 1”
  10. Functions fun add(a: Int, b: Int) = a + b

    fun log(num: Int, msg: String) = println(“$msg $num”) Calling functions: add(1, 3) log(1, “Num is”) //“Num is 1”
  11. Functions fun add(a: Int = 0, b: Int = 0)

    = a + b fun log(num: Int, msg: String = “Num is”) = println(“$msg $num”) add() //returns 0 add(1) //returns 1 add(b = 1) //returns 1 log(1) // “Num is 1” log(msg = “Its ”, num = 2) // “Its 2”
  12. Classes and data classes @Override public boolean equals(Object o) {

    if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; User user = (User) o; if (age != user.age) return false; if (!name.equals(user.name)) return false; return email.equals(user.email); } @Override public int hashCode() { int result = name.hashCode(); result = 31 * result + email.hashCode(); result = 31 * result + age; return result; } } class User { private final String name; private final String email; private final int age; User(String name, String email, int age) { this.name = name; this.email = email; this.age = age; } public String getName() { return name; } public String getEmail() { return email; } public int getAge() { return age; } @Override public String toString() { return "User{ name='" + name + '\'' + ", email='" + email + '\'' + ", age=" + age + '}'; }
  13. Classes and data classes @Override public boolean equals(Object o) {

    if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; User user = (User) o; if (age != user.age) return false; if (!name.equals(user.name)) return false; return email.equals(user.email); } @Override public int hashCode() { int result = name.hashCode(); result = 31 * result + email.hashCode(); result = 31 * result + age; return result; } } class User { private final String name; private final String email; private final int age; User(String name, String email, int age) { this.name = name; this.email = email; this.age = age; } public String getName() { return name; } public String getEmail() { return email; } public int getAge() { return age; } @Override public String toString() { return "User{ name='" + name + '\'' + ", email='" + email + '\'' + ", age=" + age + '}'; }
  14. Classes and data classes @Override public boolean equals(Object o) {

    if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; User user = (User) o; if (age != user.age) return false; if (!name.equals(user.name)) return false; return email.equals(user.email); } @Override public int hashCode() { int result = name.hashCode(); result = 31 * result + email.hashCode(); result = 31 * result + age; return result; } class User ( val name: String, val email: String, val age: Int ) @Override public String toString() { return "User{ name='" + name + '\'' + ", email='" + email + '\'' + ", age=" + age + '}'; }
  15. Classes and data classes data class User ( val name:

    String, val email: String, val age: Int ) val user = User("John Smith", "[email protected]", 24) val newUser = user.copy(name = "Sam") //newUser == User("Sam", "[email protected]", 24) val (name, email, age) = newUser
  16. Data classes data class User ( val name: String =

    "John Smith", val email: String = "[email protected]", val age: Int = 24 ) val user = User () // user == User("John Smith", "[email protected]", 24)
  17. Classes and data classes data class User( val name: String,

    val email: String, val age: Int) • Kotlin classes are final by default • we need to annotate class as open, if we want to inherit them • data classes can’t be inherited class limitations:
  18. Classes and data classes open class User( val name: String,

    val email: String, val age: Int) • Kotlin classes are final by default • we need to annotate class as open, if we want to inherit them • data classes can’t be inherited class limitations:
  19. Extension functions fun String.swapSpacesForUnderscore(): String = this.replace(" ", "_") "This

    is random message!".swapSpacesForUnderscore() // returns "This_is_random_message!" Compiles to: public static final String swapSpacesForUnderscore(@NotNull String $receiver) { Intrinsics.checkParameterIsNotNull($receiver, "$receiver"); return $receiver.replace(," ", "_"); }
  20. Extension functions package com.app.android.util fun String.swapSpacesForUnderscore(): String = this.replace(" ",

    "_") package com.app.android.main "Random text!".swapSpacesForUnderscore()
  21. Extension functions package com.app.android.util fun String.swapSpacesForUnderscore(): String = this.replace(" ",

    "_") package com.app.android.main import com.app.android.util.swapSpacesForUnderscore "Random text!".swapSpacesForUnderscore()
  22. Extension properties val Array<String>.lastElement: String get() = this[size - 1]

    val names: Array<String> = arrayOf("John", "Will", "Emma", "Peter") val name = names.lastElement //returns "Peter" Compiles to: public static final String getLastElement(@NotNull String[] $receiver) { Intrinsics.checkParameterIsNotNull($receiver, "$receiver"); return $receiver[$receiver.length - 1]; }
  23. Extension properties val <T> Array<T>.lastElement: T get() = this[size -

    1] val names: Array<String> = arrayOf("John", "Will", "Emma", "Peter") val name = names.lastElement //returns "Peter" Compiles to: public static final Object getLastElement(@NotNull Object[] $receiver) { Intrinsics.checkParameterIsNotNull($receiver, "$receiver"); return $receiver[$receiver.length - 1]; }
  24. Extension properties val <T> Array<T>.lastElement: T get() = this[size -

    1] val nums: Array<Int> = arrayOf(1, 2, 3, 4) val num = nums.lastElement //returns 4 Compiles to: public static final Object getLastElement(@NotNull Object[] $receiver) { Intrinsics.checkParameterIsNotNull($receiver, "$receiver"); return $receiver[$receiver.length - 1]; }
  25. Android extensions plugin class MainActivity : AppCompatActivity() { override fun

    onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val toolbar: Toolbar = findViewById(R.id.toolbar) as Toolbar setSupportActionBar(toolbar) val fab: FloatingActionButton = findViewById(R.id.fab) as FloatingActionButton fab.setOnClickListener { Toast.makeText(this, "Hello!", Toast.LENGTH_SHORT).show() } } }
  26. Android extensions plugin class MainActivity : AppCompatActivity() { @BindView(R.id.toolbar) Toolbar

    toolbar; @BindView(R.id.fab) FloatingActionButton fab; override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) ButterKnife.bind(this) setSupportActionBar(toolbar) fab.setOnClickListener { Toast.makeText(this, "Hello!", Toast.LENGTH_SHORT).show() } } }
  27. Android extensions plugin import kotlinx.android.synthetic.main.activity_main.toolbar import kotlinx.android.synthetic.main.activity_main.fab class MainActivity :

    AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) setSupportActionBar(toolbar) fab.setOnClickListener { Toast.makeText(this, "Hello!", Toast.LENGTH_SHORT).show() } } }
  28. Android extensions plugin import kotlinx.android.synthetic.main.activity_main.toolbar import kotlinx.android.synthetic.main.activity_main.fab class MainActivity :

    AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) setSupportActionBar(toolbar) fab.setOnClickListener { Toast.makeText(this, "Hello!", Toast.LENGTH_SHORT).show() } } }
  29. Android extensions plugin import kotlinx.android.synthetic.main.activity_main.toolbar import kotlinx.android.synthetic.main.activity_main.loging_btn_registration_fragment class MainActivity :

    AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) setSupportActionBar(toolbar) loging_btn_registration_fragment.setOnClickListener { Toast.makeText(this, "Hello!", Toast.LENGTH_SHORT).show() } } }
  30. Android extensions plugin import kotlinx.android.synthetic.main.activity_main.toolbar import kotlinx.android.synthetic.main.activity_main.loging_btn_registration_fragment as login class

    MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) setSupportActionBar(toolbar) login.setOnClickListener { Toast.makeText(this, "Hello!", Toast.LENGTH_SHORT).show()} } }
  31. Function expressions val add: (Int, Int) -> Int = {

    x,y -> x+y } add(1,2) val validator: (String) -> Boolean ={ value -> value.contains("@") } validator("[email protected]") • function expressions are blocks of code which we can instantiate(represent as type)
  32. Function expressions val add: (Int, Int) -> Int = {

    x,y -> x+y } add(1,2) • function expressions are blocks of code which we can instantiate(represent as type) val validator: (String) -> Boolean ={ it.contains("@") } validator("[email protected]")
  33. Function expressions val add: (Int, Int) -> Int = {

    x,y -> x+y } add(1,2) val validator: (String) -> Boolean ={ it.contains("@") } validator("[email protected]") mailTextview.validateWith{ validator("[email protected]") } • function expressions are blocks of code which we can instantiate(represent as type)
  34. Higher order functions fun <T> List<T>.filter(predicate: (T) -> Boolean): List<T>{

    val items = ArrayList<T>() for (item in this) { } return items }
  35. Higher order functions fun <T> List<T>.filter(predicate: (T) -> Boolean): List<T>{

    val items = ArrayList<T>() for (item in this) { if (predicate(item)) { items.add(item) } } return items } val cars = listOf("BMW", "Fiat", "Mercedes", "KIA", "Ford") val filteredCars = cars.filter ({ it.startsWith("F") }) // filteredCars == listOf("Fiat", "Ford")
  36. Higher order functions fun <T> List<T>.filter(predicate: (T) -> Boolean): List<T>{

    val items = ArrayList<T>() for (item in this) { if (predicate(item)) { items.add(item) } } return items } val cars = listOf("BMW", "Fiat", "Mercedes", "KIA", "Ford") val filteredCars = cars.filter { it.startsWith("F") } // filteredCars == listOf("Fiat", "Ford")
  37. Quick overview • Extension functions - adds functionality to types

    without overriding existing methods • Function expressions - undeclared function body used as an expression • Higher order function - function that accepts function or returns function
  38. fun saveUser(user: User) { val editor = sharedPref.edit() editor.putString(ACCESS_TOKEN, user.token)

    editor.putString(USER_EMAIL, user.email) editor.commit() } Extension / Higher order function expression combo fun SharedPreferences.edit(editor : SharedPreferences.Editor, func: () -> Unit) { func() editor.commit() }
  39. Extension / Higher order function expression combo fun saveUser(user: User)

    { val editor = sharedPref.edit() sharedPref.edit(editor) { editor.putString(ACCESS_TOKEN, user.token) editor.putString(USER_EMAIL, user.email) } } fun SharedPreferences.edit(editor : SharedPreferences.Editor, func: () -> Unit) { func() editor.commit() }
  40. fun saveUser(user: User) { val editor = sharedPref.edit() sharedPref.edit(editor) {

    editor.putString(ACCESS_TOKEN, user.token) editor.putString(USER_EMAIL, user.email) } } Extension / Higher order function expression combo fun SharedPreferences.edit(editor : SharedPreferences.Editor, func: () -> Unit) { func() editor.commit() }
  41. fun saveUser(user: User) { sharedPref.edit { editor.putString(ACCESS_TOKEN, user.token) editor.putString(USER_EMAIL, user.email)

    } } Extension / Higher order function expression combo fun SharedPreferences.edit(func: () -> Unit) { val editor = edit() func() editor.commit() }
  42. fun saveUser(user: User) { sharedPref.edit { it.putString(ACCESS_TOKEN, user.token) it.putString(USER_EMAIL, user.email)

    } } Extension / Higher order function expression combo fun SharedPreferences.edit(func: (SharedPreferences.Editor) -> Unit) { val editor = edit() func(editor) editor.commit() }
  43. fun saveUser(user: User) { sharedPref.edit { it.putString(ACCESS_TOKEN, user.token) it.putString(USER_EMAIL, user.email)

    } } Extension / Higher order function expression combo fun SharedPreferences.edit(func: (SharedPreferences.Editor) -> Unit) { val editor = edit() func(editor) editor.commit() }
  44. fun saveUser(user: User) { sharedPref.edit { it.putString(ACCESS_TOKEN, user.token) it.putString(USER_EMAIL, user.email)

    } } Extension / Higher order function expression combo fun SharedPreferences.edit(func: SharedPreferences.Editor.() -> Unit)) { val editor = edit() func(editor) editor.commit() }
  45. fun saveUser(user: User) { sharedPref.edit { it.putString(ACCESS_TOKEN, user.token) it.putString(USER_EMAIL, user.email)

    } } Extension / Higher order function expression combo fun SharedPreferences.edit(func: SharedPreferences.Editor.() -> Unit)) { val editor = edit() editor.func() editor.commit() }
  46. fun saveUser(user: User) { sharedPref.edit { putString(ACCESS_TOKEN, user.token) putString(USER_EMAIL, user.email)

    } } Extension / Higher order function expression combo fun SharedPreferences.edit(func: SharedPreferences.Editor.() -> Unit) { val editor = edit() editor.func() editor.commit() }
  47. Extension / Higher order function expression combo fun SharedPreferences.Editor.put(pair: Pair<String,

    Any>) { val key = pair.first val value = pair.second when(value) { is String -> putString(key, value) is Int -> putInt(key, value) is Boolean -> putBoolean(key, value) is Float -> putFloat(key, value) is Long -> putLong(key, value) else -> error(“Only primitive types are supported”) } }
  48. fun saveUser(user: User) { sharedPref.edit { putString(ACCESS_TOKEN, user.token) putString(USER_EMAIL, user.email)

    } } Extension / Higher order function expression combo fun SharedPreferences.edit(func: SharedPreferences.Editor.() -> Unit)) { val editor = edit() editor.func() editor.commit() }
  49. Extension / Higher order function expression combo fun saveUser(user: User)

    { sharedPref.edit { put(Pair(ACCESS_TOKEN, user.token)) put(Pair(USER_EMAIL, user.email)) } } fun SharedPreferences.edit(func: SharedPreferences.Editor.() -> Unit) { val editor = edit() editor.func() editor.commit() }
  50. fun saveUser(user: User) { sharedPref.edit { put(ACCESS_TOKEN to user.token) put(USER_EMAIL

    to user.email) } } Extension / Higher order function expression combo fun SharedPreferences.edit(func: SharedPreferences.Editor.() -> Unit) { val editor = edit() editor.func() editor.commit() }
  51. fun saveUser(user: User) { sharedPref.edit { put(ACCESS_TOKEN to user.token) put(USER_EMAIL

    to user.email) } } Extension / Higher order function expression combo fun SharedPreferences.edit(func: SharedPreferences.Editor.() -> Unit) { val editor = edit() editor.func() editor.commit() } public infix fun <A, B> A.to(that: B): Pair<A, B> = Pair(this, that)
  52. fun saveUser(user: User) { sharedPref.edit { put(ACCESS_TOKEN to user.token) put(USER_EMAIL

    to user.email) } } Extension / Higher order function expression combo inline fun SharedPreferences.edit(func: SharedPreferences.Editor.() -> Unit) { val editor = edit() editor.func() editor.commit() }
  53. Extension / Higher order function expression combo From this: fun

    saveUser(user: User) { val editor = sharedPref.edit() editor.putString(ACCESS_TOKEN, user.token) editor.putString(USER_EMAIL, user.email) editor.commit() } To this: inline fun saveUser(user: User) { sharedPref.edit { put(ACCESS_TOKEN to user.token) put(USER_EMAIL to user.email) } }
  54. Summary • immutable and mutable variables • nullability • functions(default

    values and named arguments) • classes and data classes • extension functions and properties • function expression • higher order functions • ultra mega giga combo of three above concepts • use inline modifier
  55. Resources • Official Kotlin documentation • Official Kotlin Github •

    Anko • Kotlin koans • Awesome Kotlin – collection of materials • Slack kanal • Design patterns in Kotlin • Keddit - demo app • Kotlin For Android (at DevFest İzmir 2016) • Kotlin – Ready for Production – Hadi Hariri • Android development with Kotlin – Jake Wharton
  56. Nebojša Vukšić Android developer @ codecentric Founder of Kotlin User

    Group Serbia Nesh_Wolf [email protected] Kotlin User Group Serbia https://www.meetup.com/Serbia-Kotlin-User-Group https://www.facebook.com/kotlinserbia/ https://twitter.com/kotlin_serbia