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

AndroidDev Powered by Kotlin

AndroidDev Powered by Kotlin

A talk about the language features that android developers can take advantage of.

Presented at droidcon Dubai 2018 (droidcon.ae)
Video available: https://www.youtube.com/watch?v=ofysYx1TEpA

Segun Famisa

April 14, 2018
Tweet

More Decks by Segun Famisa

Other Decks in Programming

Transcript

  1. #AndroidDev
    Powered by Kotlin!
    making the most of Kotlin for Android dev

    View Slide

  2. Android Engineer at trivago
    [email protected]
    Oluwasegun Famisa

    View Slide

  3. 190 countries
    55 global regions
    1.8m+ hotels
    Founded in 2005
    Hotel search and price comparison
    Available on Android, iOS, Web, PWA

    View Slide

  4. About Kotlin

    View Slide

  5. About Kotlin

    View Slide

  6. - Functional vs Imperative
    programming

    View Slide

  7. Imperative == structured in steps of execution
    and usually reads as “how it’s done”

    View Slide

  8. Functional == actions are composed into
    functions and usually reads as “what is done”
    Imperative == structured in steps of execution
    and usually reads as “how it’s done”

    View Slide

  9. // Java - print even numbers
    for (int i = start; i < end; i++) {
    if (i % 2 == 0) {
    System.out.println(i);
    }
    }

    View Slide

  10. // Java - print even numbers
    for (int i = start; i < end; i++) {
    if (i % 2 == 0) {
    System.out.println(i);
    }
    }
    // Kotlin - print even numbers
    (start until end)
    .filter { it % 2 == 0 }
    .map { println(it) }

    View Slide

  11. Imperative Functional
    Immutability isn’t
    encouraged at language
    level
    Encourages immutability
    Instances of classes,
    structures, objects are
    first class citizens
    Functions are first class
    citizens
    Loops, method calls,
    conditionals
    Function calls
    Side-effects allowed in
    functions
    Pure functions

    View Slide

  12. Some interesting
    features

    View Slide

  13. - nullable types

    View Slide

  14. Kotlin introduces nullability.
    At the time of instantiating an object, you
    tell the compiler whether the object can be
    null or not

    View Slide

  15. val name: String = null // error (non-nullable type)
    val email: String? = null // works fine (nullable type)

    View Slide

  16. val name: String = “Segun”
    val email: String? = null
    name.length // works fine
    email.length // compiler error (unsafe access)
    email?.length // works fine (safe access)

    View Slide

  17. Free from NullPointerException!

    View Slide

  18. Free from NullPointerException!
    Except you...
    1. throw NullPointerException
    2. use the “!!”
    3. call Java code that causes it

    View Slide

  19. - immutability

    View Slide

  20. “Classes should be immutable unless there's a
    very good reason to make them mutable.”
    - Joshua Bloch (Effective Java)

    View Slide

  21. Immutable objects == thread-safe

    View Slide

  22. // Immutable class in Java
    public final class User {
    // private fields
    private final int id;
    private final int email;
    // public constructor
    public User(int id, String email){...}
    // Getters
    public int getId() {...}
    public String getEmail() {...}
    // No public setters
    ...
    }

    View Slide

  23. // Immutable class in Java
    public final class User {
    // private fields
    private final int id;
    private final int email;
    // public constructor
    public User(int id, String email){...}
    // Getters
    public int getId() {...}
    public String getEmail() {...}
    // No public setters
    ...
    }
    // Immutable class in Kotlin
    class User(val id: Int,
    val email: String)

    View Slide

  24. // Immutable class in Kotlin
    class User(val id: Int, val email: String)
    Classes are final by default in Kotlin. To
    make a class non-final, you have to use the
    “open”

    View Slide

  25. // Immutable class in Kotlin
    class User(val id: Int, val email: String)
    Classes are final by default in Kotlin. To
    make a class non-final, you have to use the
    “open”
    open class User(val id: Int, val email: String)

    View Slide

  26. // Immutable class in Kotlin
    class User(val id: Int, val email: String)
    val vs var

    View Slide

  27. // Immutable class in Kotlin
    class User(val id: Int, val email: String)
    val vs var
    val is like final in Java. Once created,
    cannot be re-assigned value
    var can be re-assigned another value

    View Slide

  28. Quick tip: Reading generated Java
    code helps with better understanding

    View Slide

  29. 1

    View Slide

  30. 2

    View Slide

  31. 3

    View Slide

  32. - data classes

    View Slide

  33. // Data holding class in Java
    public final class User {
    ...
    public User(int id, String email){...}
    // Getters
    public final int getId() {...}
    public final String getEmail() {...}
    }

    View Slide

  34. // Data holding class in Java
    public final class User {
    ...
    public User(int id, String email){...}
    // Getters
    public final int getId() {...}
    public final String getEmail() {...}
    }
    // Kotlin
    data class User(
    val id: Int,
    val email: String
    )

    View Slide

  35. data class User(
    val id: Int,
    val email: String
    )
    // Generated Java code
    public final class User {
    ...
    public User(int id, String email){...}
    // Getters
    public final int getId() {...}
    public final String getEmail() {...}
    public String toString() {...}
    public int hashCode() {...}
    public boolean equals(Object o) {...}
    ...
    }

    View Slide

  36. // Generated Java code
    public final class User {
    ...
    ...
    public final int component1() {...}
    public final String component2() {...}
    public final User copy(...) {...}
    }
    data class User(
    val id: Int,
    val email: String
    )

    View Slide

  37. Kotlin data classes allow us do something
    called “destructuring declaration”

    View Slide

  38. // Person data class
    data class Person(val name: String, val age: Int)

    View Slide

  39. // Person data class
    data class Person(val name: String, val age: Int)
    // Destructure
    val (name, age) = person

    View Slide

  40. // Person data class
    data class Person(val name: String, val age: Int)
    // Destructure
    val (name, age) = person
    But how?

    View Slide

  41. // Person data class
    data class Person(val name: String, val age: Int)
    // Generated functions
    public final String component1() {...} // name

    View Slide

  42. // Person data class
    data class Person(val name: String, val age: Int)
    // Generated functions
    public final String component1() {...} // name
    public final int component2() {...} // age

    View Slide

  43. // Person data class
    data class Person(val name: String, val age: Int..)
    // Generated functions
    public final String component1() {...} // name
    public final int component2() {...} // age
    ...
    public final Type componentN() {...} //nth data class arg

    View Slide

  44. // Person data class
    data class Person(val name: String, val age: Int)
    // Destructure
    val (name, age) = person
    // Same as
    val name = person.component1()
    val age = person.component2()

    View Slide

  45. // Person data class
    data class Person(val name: String, val age: Int)
    val people = getPeople()
    // Use destructuring in for loops
    for ((name, age) in people) {...}

    View Slide

  46. // Person data class
    data class Person(val name: String, val age: Int)
    val people = getPeople()
    // Use destructuring in for loops
    for ((name, age) in people) {...}

    View Slide

  47. Some potential use cases for data class in Android:
    ● Retrofit request & response classes
    ● Domain models
    ● Entities

    View Slide

  48. - sealed classes

    View Slide

  49. ● Sealed classes are like enums but even better.
    ● We can use them to solve many everyday Android
    situations.

    View Slide

  50. sealed class Result {
    class Success(val value: Any) : Result()
    class Error(val errorMessage: String) : Result()
    }

    View Slide

  51. // Usage:
    when (result) {
    is Result.Success -> // do something with result.value
    is Result.Error -> // do something with result.errorMessage
    }
    sealed class Result {
    class Success(val value: Any) : Result()
    class Error(val errorMessage: String) : Result()
    }

    View Slide

  52. // Usage:
    when (result) {
    is Result.Success -> // do something with result.value
    is Result.Error -> // do something with result.errorMessage
    }
    But how does
    it work?
    sealed class Result {
    class Success(val value: Any) : Result()
    class Error(val errorMessage: String) : Result()
    }

    View Slide

  53. // Java
    public abstract class Result {
    public static final class Success extends Result {...}
    public static final class Error extends Result {...}
    }
    // Kotlin
    sealed class Result {
    class Success(val value: Any) : Result()
    class Error(val errorMessage: String) : Result()
    }

    View Slide

  54. - functions are fun!

    View Slide

  55. Functions are first class citizens!!!

    View Slide

  56. Functions are first class citizens!!!
    They can:
    1. be stored in a variable - just like other types
    2. take another function as parameter
    3. return a function

    View Slide

  57. Functions are first class citizens!!!
    They can:
    1. be stored in a variable - just like other types
    2. take another function as parameter
    3. return a function
    a.k.a “Higher order function”

    View Slide

  58. Higher order function
    fun atLeastAndroidO(action: () -> Unit) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    action()
    }
    }

    View Slide

  59. Higher order function
    fun atLeastAndroidO(action: () -> Unit) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    action()
    }
    }

    View Slide

  60. Higher order function
    fun atLeastAndroidO(action: () -> Unit) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    action()
    }
    }
    // Usage:
    atLeastAndroidO {
    // do something requiring Android O
    }

    View Slide

  61. // Kotlin higher order function
    fun atLeastAndroidO(action: () -> Unit) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    action()
    }
    }
    // Generated Java code
    public final void atLeastAndroidO(Function0 action) {
    if (VERSION.SDK_INT >= 26) {
    action.invoke();
    }
    }

    View Slide

  62. // Kotlin higher order function
    fun atLeastAndroidO(action: () -> Unit) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    action()
    }
    }
    // Generated Java code
    public final void atLeastAndroidO(Function0 action) {
    if (VERSION.SDK_INT >= 26) {
    action.invoke();
    }
    }
    Every lambda is an object.
    Not good for performance

    View Slide

  63. - inline functions

    View Slide

  64. // Kotlin higher order function
    inline fun atLeastAndroidO(action: () -> Unit) {...}
    // Use like this:
    fun doSomethingOnOreo() {
    atLeastAndroidO { println("Hey, running on O") }
    }

    View Slide

  65. // Kotlin higher order function
    inline fun atLeastAndroidO(action: () -> Unit) {...}
    // Use like this
    fun doSomethingOnOreo() {
    atLeastAndroidO { println("Hey, running on O") }
    }
    // Generated code
    // Unused generated method
    void atLeastAndroidO(Function0 action) {...}
    void doSomethingOnOreo() {
    if (VERSION.SDK_INT >= 26) {
    System.out.println("Hey, running on O");
    }
    }

    View Slide

  66. // Kotlin higher order function
    inline fun atLeastAndroidO(action: () -> Unit) {...}
    // Use like this
    fun doSomethingOnOreo() {
    atLeastAndroidO { println("Hey, running on O") }
    }
    method body is copied to the call-site
    // Generated code
    // Unused generated method
    void atLeastAndroidO(Function0 action) {...}
    void doSomethingOnOreo() {
    if (VERSION.SDK_INT >= 26) {
    System.out.println("Hey, running on O");
    }
    }

    View Slide

  67. - extension functions

    View Slide

  68. ● Extend existing classes, even those we don’t own.
    Extension functions allow us:

    View Slide

  69. ● Extend existing classes, even those we don’t own.
    ● Improve code readability
    Extension functions allow us:

    View Slide

  70. ● Extend existing classes, even those we don’t own.
    ● Improve code readability
    ● Get rid of Utils.java or Utils.kt classes
    Extension functions allow us:

    View Slide

  71. ● Extend existing classes, even those we don’t own.
    ● Improve code readability
    ● Get rid of Utils.java or Utils.kt classes
    Extension functions allow us:
    But how?

    View Slide

  72. Extension functions are resolved statically.
    // Kotlin ext fun
    fun Int.isEven(): Boolean {
    return this and 1 == 0
    }

    View Slide

  73. Extension functions are resolved statically.
    // Kotlin ext fun
    fun Int.isEven(): Boolean {
    return this and 1 == 0
    }
    // Java generated code
    public static final boolean isEven(int $receiver) {
    return ($receiver & 1) == 0;
    }

    View Slide

  74. Extension functions are resolved statically.
    // Kotlin ext fun
    fun Int.isEven(): Boolean {
    return this and 1 == 0
    }
    // Java generated code
    public static final boolean isEven(int $receiver) {
    return ($receiver & 1) == 0;
    }
    // Usage
    1.isEven() // evaluates to false

    View Slide

  75. ● Set of Kotlin Extensions for Android development
    Android KTX

    View Slide

  76. Android KTX
    // Without Android KTX
    val fileUri = Uri.fromFile(...)

    View Slide

  77. Android KTX
    // Without Android KTX
    val fileUri = Uri.fromFile(...)
    // With Android KTX
    val fileUri = file.toUri()

    View Slide

  78. Android KTX
    // Without Android KTX
    val fileUri = Uri.fromFile(...)
    // With Android KTX
    val fileUri = file.toUri()
    // Under the hood
    inline fun File.toUri(): Uri = Uri.fromFile(this)

    View Slide

  79. // Iterating through a ViewGroup's children
    for (i in 0 until viewGroup.childCount) {
    val view = viewGroup.getChildAt(i)
    // do something with view
    }

    View Slide

  80. operator fun ViewGroup.iterator() = object : MutableIterator {
    private var index = 0
    override fun hasNext() = index < childCount
    override fun next() = getChildAt(index++)
    override fun remove() = removeViewAt(--index)
    }

    View Slide

  81. operator fun ViewGroup.iterator() = object : MutableIterator {
    private var index = 0
    override fun hasNext() = index < childCount
    override fun next() = getChildAt(index++)
    override fun remove() = removeViewAt(--index)
    }
    Extension function on ViewGroup class!

    View Slide

  82. operator fun ViewGroup.iterator() ...
    // Now we can do this
    for (view in viewGroup) {
    // do something with view
    }

    View Slide

  83. Android KTX
    There’s more! Check out:
    https://github.com/android/android-ktx

    View Slide

  84. - operator overloading

    View Slide

  85. ● Custom behaviour for standard
    operators
    Operator overloading allows us to:

    View Slide

  86. ● Custom behaviour for standard
    operators
    ● Implement for our own classes as well
    as other classes we don’t own.
    Operator overloading allows us to:

    View Slide

  87. ● Custom behaviour for standard
    operators
    ● Implement for our own classes as well
    as other classes we don’t own.
    Operator overloading allows us to:
    Implemented by using the operator keyword
    //Example
    operator fun ViewGroup.iterator() ...

    View Slide

  88. // Product
    data class Product(val price: Double)
    TODO("Easily determine whether the price
    of a product is higher than another")

    View Slide

  89. // Product
    data class Product(val price: Double)
    TODO("Easily determine whether the price
    of a product is higher than another")
    There’s an a̶p̶p̶ operator for that

    View Slide

  90. // Product
    data class Product(val price: Double) {
    operator fun compareTo(other: Product): Int {
    return this.price.compareTo(other.price)
    }
    }

    View Slide

  91. // Product
    data class Product(val price: Double) {
    operator fun compareTo(other: Product): Int {
    return this.price.compareTo(other.price)
    }
    }
    >
    <
    >=
    <=

    View Slide

  92. // Product
    data class Product(val price: Double) {
    operator fun compareTo(other: Product): Int {
    return this.price.compareTo(other.price)
    }
    }
    // Usage
    val productA = Product(price = 200.00)
    val productB = Product(price = 800.00)
    productA > productB // evaluates to false
    productA < productB // evaluates to true

    View Slide

  93. Let’s see another example of operator
    overloading

    View Slide

  94. data class ShoppingCart(val items: MutableList)

    View Slide

  95. data class ShoppingCart(val items: MutableList)
    TODO("Ability to add a new product to the
    shopping cart")

    View Slide

  96. data class ShoppingCart(val items: MutableList)
    TODO("Ability to add a new product to the
    shopping cart")
    val cart = createEmptyCart()
    // one way to go
    cart.items.add(product)

    View Slide

  97. data class ShoppingCart(val items: MutableList)
    TODO("Ability to add a new product to the
    shopping cart")
    val cart = createEmptyCart()
    // one way to go
    cart.items.add(product)

    View Slide

  98. data class ShoppingCart(val items: MutableList) {
    operator fun plusAssign(product: Product) {
    items.add(product)
    }
    }

    View Slide

  99. data class ShoppingCart(val items: MutableList) {
    operator fun plusAssign(product: Product) {
    items.add(product)
    }
    }
    // Usage of the plusAssign operator function
    val cart = createEmptyCart()
    cart += Product(price = 12.00)

    View Slide

  100. // Usage of the plusAssign operator function
    val cart = createEmptyCart()
    cart += Product(price = 12.00)
    data class ShoppingCart(val items: MutableList) {
    operator fun plusAssign(product: Product) {
    items.add(product)
    }
    }

    View Slide

  101. ...
    operator fun inc() ...// a++
    operator fun dec() ...// a--
    operator fun plus(other: T) ...// a + b
    operator fun minus(other: T) ...// a - b
    operator fun get(index: Int) ...// a[i]
    operator fun contains(item: T) ...// a in b
    ...
    More examples:

    View Slide

  102. - interoperability

    View Slide

  103. - platform type
    Calling Java code from Kotlin

    View Slide

  104. String! String?
    Pop
    What are thossseeee nullability types?
    String

    View Slide

  105. String String! String?
    Non-nullable
    type
    Nullable
    type
    Platform type
    Kotlin compiler has
    no idea whether
    it’s nullable or
    not

    View Slide

  106. Types are very important when considering
    interoperability between Java & Kotlin

    View Slide

  107. // Java
    @NotNull
    public String getName() {
    return "Segun";
    }
    ...
    // Calling Java from Kotlin
    // Compiles fine
    val nameLength = myClass.name.length

    View Slide

  108. // Java
    @Nullable
    public String getName() {
    return “Segun”;
    }
    ...
    // Calling Java from Kotlin
    // Compiler error
    val nameLength = myClass.name.length

    View Slide

  109. // Java
    @Nullable
    public String getName() {
    return “Segun”;
    }
    ...
    // Calling Java from Kotlin
    // Compiles fine
    val nameLength = myClass.name?.length

    View Slide

  110. // Java
    public String getName() {
    return null;
    }
    ...
    // Calling Java from Kotlin
    // Compiles fine. Throws NullPointer in runtime
    val nameLength = myClass.name.length

    View Slide

  111. // Java
    public String getName() {
    return null;
    }
    ...
    // Calling Java from Kotlin
    // Compiles fine. Evaluates to null
    val nameLength = myClass.name?.length

    View Slide

  112. ...
    @NotNull
    public String getName() {
    return "Segun";
    }
    ...
    @Nullable
    public String getName() {
    return "Segun";
    }
    ...
    public String getName() {
    return "Segun";
    }
    ...
    String
    String?
    String!

    View Slide

  113. Example of this in Android framework code!
    // Support library < 27
    class Fragment {
    ...
    final public FragmentActivity getActivity() {
    return mHost == null ? null : (FragmentActivity) mHost.getActivity();
    }
    }

    View Slide

  114. Example of this in Android framework code!
    // Support library < 27
    class Fragment {
    ...
    final public FragmentActivity getActivity() {
    return mHost == null ? null : (FragmentActivity) mHost.getActivity();
    }
    }
    // compiles ok but could throw an exception in runtime!
    activity.supportActionBar = ...

    View Slide

  115. Example of this in Android framework code!
    // Support library >= 27
    class Fragment {
    ...
    @Nullable
    final public FragmentActivity getActivity() {
    return mHost == null ? null : (FragmentActivity) mHost.getActivity();
    }
    }

    View Slide

  116. Example of this in Android framework code!
    // Support library >= 27
    class Fragment {
    ...
    @Nullable
    final public FragmentActivity getActivity() {
    return mHost == null ? null : (FragmentActivity) mHost.getActivity();
    }
    }
    // compiler error! Should use safe access
    activity.supportActionBar = ...

    View Slide

  117. Example of this in Android framework code!
    // Support library >= 27
    class Fragment {
    ...
    @Nullable
    final public FragmentActivity getActivity() {
    return mHost == null ? null : (FragmentActivity) mHost.getActivity();
    }
    }
    // compiles ok, safe in runtime too
    activity?.supportActionBar = ...

    View Slide

  118. @JvmOverloads

    View Slide

  119. @JvmOverloads
    Generates overloaded methods and constructors for
    class signatures and methods that have default
    values

    View Slide

  120. @JvmOverloads
    Generates overloaded methods and constructors for
    class signatures and methods that have default
    values
    Example??

    View Slide

  121. // Kotlin class without @JvmOverloads
    class Point(val label: String, val x: Double = 0.0, val y: Double = 0.0)

    View Slide

  122. // Kotlin class without @JvmOverloads
    class Point(val label: String, val x: Double = 0.0, val y: Double = 0.0)
    // Generated constructor
    public Point(@NotNull String label, double x, double y)

    View Slide

  123. // Kotlin class without @JvmOverloads
    class Point(val label: String, val x: Double = 0.0, val y: Double = 0.0)
    // Kotlin class with @JvmOverloads
    class Point @JvmOverloads constructor(val label: String, val x: Double = 0.0,
    val y: Double = 0.0)

    View Slide

  124. // Kotlin class without @JvmOverloads
    class Point(val label: String, val x: Double = 0.0, val y: Double = 0.0)
    // Generated constructors
    public Point(@NotNull String label)
    public Point(@NotNull String label, double x)
    public Point(@NotNull String label, double x, double y)
    // Kotlin class with @JvmOverloads
    class Point @JvmOverloads constructor(val label: String, val x: Double = 0.0,
    val y: Double = 0.0)

    View Slide

  125. @JvmField

    View Slide

  126. @JvmField
    Helps to expose a Kotlin class property as a Java
    field.
    Example??

    View Slide

  127. class Data(val value: Int...) : Parcelable {
    private constructor(parcel: Parcel)...
    ...
    companion object {
    val CREATOR: Parcelable.Creator = ...
    }
    }

    View Slide

  128. class Data(val value: Int...) : Parcelable {
    private constructor(parcel: Parcel)...
    ...
    companion object {
    val CREATOR: Parcelable.Creator = ...
    }
    }
    Compiler error.
    Documentation says:
    Classes implementing the Parcelable interface must also have a
    non-null static field called CREATOR of a type that implements the
    Parcelable.Creator interface.

    View Slide

  129. class Data(val value: Int...) : Parcelable {
    private constructor(parcel: Parcel)...
    ...
    companion object {
    @JvmField
    val CREATOR: Parcelable.Creator = ...
    }
    }
    CREATOR is exposed as a field, and everything is good!

    View Slide

  130. @JvmStatic
    @JvmName
    @JvmMultifileClass... etc
    There’s more:

    View Slide

  131. Code reviews in Kotlin

    View Slide

  132. Look out for imperative styles

    View Slide

  133. // Imperative - Java-ish style
    fun sendMessageToClient(client: Client?,message: String?,mailer: Mailer) {
    if (client == null || message == null) return
    val personalInfo = client.personalInfo ?: return
    val email = personalInfo.email ?: return
    mailer.sendMessage(email, message)
    }

    View Slide

  134. // Imperative - Java-ish style
    fun sendMessageToClient(client: Client?,message: String?,mailer: Mailer) {
    if (client == null || message == null) return
    val personalInfo = client.personalInfo ?: return
    val email = personalInfo.email ?: return
    mailer.sendMessage(email, message)
    }
    // Suggest to do this instead - more functional than imperative
    fun sendMessageToClient(client: Client?, message: String?, mailer: Mailer) {
    if (client != null && message != null) {
    client.personalInfo
    ?.email
    ?.run {
    mailer.sendMessage(this, message)
    }
    }
    }

    View Slide

  135. // Don’t do this!
    val person = Person()
    person.age = 25
    person.name = "Oluwasegun"
    person.email = "[email protected]"
    person.cars = emptyList()

    View Slide

  136. // Don’t do this!
    val person = Person()
    person.age = 25
    person.name = "Oluwasegun"
    person.email = "[email protected]"
    person.cars = emptyList()
    // suggest to do this instead - it reads better
    val person = Person().apply {
    age = 25
    name = "Oluwasegun"
    email = "[email protected]"
    cars = emptyList()
    }

    View Slide

  137. Overuse of scoping functions

    View Slide

  138. Be nice and courteous.

    View Slide

  139. Road to 100% Kotlin

    View Slide

  140. ● Add Kotlin support to your project

    View Slide

  141. ● Add Kotlin support to your project
    ● Migrate API responses to use Kotlin data classes

    View Slide

  142. ● Add Kotlin support to your project
    ● Migrate API responses to use Kotlin data classes
    ● Convert interfaces from Java to Kotlin

    View Slide

  143. ● Add Kotlin support to your project
    ● Migrate API responses to use Kotlin data classes
    ● Convert interfaces from Java to Kotlin
    ● Add tests in Kotlin

    View Slide

  144. ● Add Kotlin support to your project
    ● Migrate API responses to use Kotlin data classes
    ● Convert interfaces from Java to Kotlin
    ● Add tests in Kotlin
    ● Gradually migrate the rest of the code base

    View Slide

  145. ● Add Kotlin support to your project
    ● Migrate API responses to use Kotlin data classes
    ● Convert interfaces from Java to Kotlin
    ● Add tests in Kotlin
    ● Gradually migrate the rest of the code base
    ● Profit

    View Slide

  146. Staying up to date with Kotlin

    View Slide

  147. Staying up to date with Kotlin...
    kotlin.link
    kotlinweekly.net
    https://github.com/jetbrains/kotlin/pulls
    https://youtrack.jetbrains.com/issues/KT
    https://github.com/Kotlin/KEEP
    androidweekly.net
    KotlinConf videos
    #Kotlin on twitter

    View Slide

  148. Come join me and my team mates!
    trv.to/droidcondubai

    View Slide