$30 off During Our Annual Pro Sale. View Details »

Life is great and everything will be OK, Kotlin is here (Google IO 2017)

Life is great and everything will be OK, Kotlin is here (Google IO 2017)

Using Kotlin for Android development has grown in popularity over the past few years and is now officially supported by Google. If you are not already using Kotlin you might be wondering why and how to adopt it. In the first part of this talk, Jake will cover advancing the usage and design patterns of the language for Android development to solve larger problems. In the second part, Christina will share her experience using Kotlin in production, from mistakes to successes, and help you answer questions your team/company might ask about adopting it.

Video: https://youtu.be/fPzxfeDJDzY

Jake Wharton
PRO

May 19, 2017
Tweet

More Decks by Jake Wharton

Other Decks in Programming

Transcript

  1. +Christina Lee
    @RunChristinaRun
    +Jake Wharton
    @JakeWharton
    Kotlin is here
    Life is great and everything will be OK

    View Slide

  2. MainActivity.java
    public class MainActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    }1
    }2

    View Slide

  3. MainActivity.java
    public class MainActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    }1
    }2

    View Slide

  4. MainActivity.java
    public class MainActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    }1
    }2

    View Slide

  5. MainActivity.java
    public class MainActivity extends Activity {
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    }1
    }2
    @Nullable

    View Slide

  6. MainActivity.java
    public class MainActivity extends Activity {
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    }1
    }2

    View Slide

  7. MainActivity.kt
    class MainActivity : Activity() {
    override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    }1
    }2

    View Slide

  8. MainActivity.kt
    class MainActivity : Activity() {
    override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    }1
    }2

    View Slide

  9. MainActivity.kt
    class MainActivity : Activity() {
    override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    }1
    }2

    View Slide

  10. TextView.java
    public float getAlpha() {
    // Retrieve value...
    }

    View Slide

  11. TextView.java
    public float getAlpha() {
    // Retrieve value...
    }
    public void setAlpha(float alpha) {
    // Set value...
    }

    View Slide

  12. TextView.java
    public float getAlpha() {
    // Retrieve value...
    }
    public void setAlpha(float alpha) {
    // Set value...
    }
    TextView tv = // ...
    Log.d("MainActivity", "Alpha: " + tv.getAlpha());
    tv.setAlpha(0f);
    MainActivity.java

    View Slide

  13. TextView.java
    public float getAlpha() {
    // Retrieve value...
    }
    public void setAlpha(float alpha) {
    // Set value...
    }
    MainActivity.kt
    val tv = // ...
    Log.d("MainActivity", "Alpha: " + tv.alpha)
    tv.alpha = 0f

    View Slide

  14. TextView.java
    public float getAlpha() {
    // Retrieve value...
    }1
    public void setAlpha(float alpha) {
    // Set value...
    }2
    MainActivity.kt
    val tv = // ...
    Log.d("MainActivity", "Alpha: " + tv.alpha)
    tv.alpha = 0f

    View Slide

  15. TextView.java
    public float getAlpha() {
    // Retrieve value...
    }1
    public void setAlpha(float alpha) {
    // Set value...
    }2
    MainActivity.kt
    val tv = // ...
    Log.d("MainActivity", "Alpha: " + tv.alpha)
    tv.alpha = 0f

    View Slide

  16. TextView.java
    public float getAlpha() {
    // Retrieve value...
    }1
    public void setAlpha(float alpha) {
    // Set value...
    }2
    MainActivity.kt
    val tv = // ...
    Log.d("MainActivity", "Alpha: " + tv.alpha)
    tv.alpha = 0f

    View Slide

  17. MainActivity.java
    LinearLayout views = // ...
    for (int i = 0; i < views.getChildCount(); i++) {
    View view = views.getChildAt(i);
    // TODO do something with view
    }

    View Slide

  18. MainActivity.kt
    val views = // ...
    for (index in 0 until views.childCount) {
    val view = views.getChildAt(index)
    // TODO do something with view
    }

    View Slide

  19. MainActivity.kt
    val views = // ...
    for (index in 0 until views.childCount) {
    val view = views.getChildAt(index)
    // TODO do something with view
    }1

    View Slide

  20. MainActivity.kt
    val views = // ...
    for (index in 0 until views.childCount) {
    val view = views.getChildAt(index)
    // TODO do something with view
    }1

    View Slide

  21. MainActivity.kt
    val views = // ...
    for (index in 0 until views.childCount) {
    val view = views.getChildAt(index)
    // TODO do something with view
    }

    View Slide

  22. MainActivity.kt
    val views = // ...
    for (index in 0 until views.childCount) {Z
    val view = views.getChildAt(index)
    // TODO do something with view
    }1
    ViewGroups.kt
    fun ViewGroup.forEach(action: (View) -> Unit) {
    for (index in 0 until childCount) {
    action(getChildAt(index))
    }2
    }3
    . Each ->

    View Slide

  23. MainActivity.kt
    val views = // ...
    views.forEach {Zview ->
    // TODO do something with view
    }1
    ViewGroups.kt
    fun ViewGroup.forEach(action: (View) -> Unit) {
    for (index in 0 until childCount) {
    action(getChildAt(index))
    }2
    }3
    val = views.getChildAt(i)

    View Slide

  24. MainActivity.kt
    val views = // ...
    views.forEach {Zview ->
    // TODO do something with view
    }1
    ViewGroups.kt
    fun ViewGroup.forEach(action: (View) -> Unit) {
    for (index in 0 until childCount) {
    action(getChildAt(index))
    }2
    }3

    View Slide

  25. MainActivity.kt
    val views = // ...
    views.forEach {Zview ->
    // TODO do something with view
    }1
    ViewGroups.kt
    fun ViewGroup.forEach(action: (View) -> Unit) {
    for (index in 0 until childCount) {
    action(getChildAt(index))
    }2
    }3

    View Slide

  26. MainActivity.kt
    val views = // ...
    views.forEach {Zview ->
    // TODO do something with view
    }1
    ViewGroups.kt
    fun ViewGroup.forEach(action: (View) -> Unit) {
    for (index in 0 until childCount) {
    action(getChildAt(index))
    }2
    }3

    View Slide

  27. MainActivity.kt
    val views = // ...
    views.forEach {Zview ->
    // TODO do something with view
    }1
    ViewGroups.kt
    fun ViewGroup.forEach(action: (View) -> Unit) {
    for (index in 0 until childCount) {
    action(getChildAt(index))
    }2
    }3

    View Slide

  28. MainActivity.kt
    val views = // ...
    views.forEach {Zview ->
    // TODO do something with view
    }1
    ViewGroups.kt
    inline fun ViewGroup.forEach(action: (View) -> Unit) {
    for (index in 0 until childCount) {
    action(getChildAt(index))
    }2
    }3
    inline

    View Slide

  29. MainActivity.kt
    val views = // ...
    views.forEach {Zview ->
    // TODO do something with view
    }1
    ViewGroups.kt
    inline fun ViewGroup.forEach(action: (View) -> Unit) {
    for (index in 0 until childCount) {
    action(getChildAt(index))
    }2
    }3

    View Slide

  30. MainActivity.kt
    val views = // ...
    views.forEach {Zview -> /* ... */ }1
    views.forEachIndexed { index, view -> /* ... */ }1
    ViewGroups.kt
    inline fun ViewGroup.forEach(action: (View) -> Unit) {
    for (index in 0 until childCount) {
    action(getChildAt(index))
    }2
    }3
    inline fun ViewGroup.forEachIndexed(action: (Int, View) -> Unit) {
    for (index in 0 until childCount) {
    action(index, getChildAt(index))
    }
    }
    /
    / T
    O
    D
    O d
    o s
    o
    m
    e
    t
    h
    i
    n
    g w
    i
    t
    h v
    i
    e
    w

    View Slide

  31. MainActivity.kt
    val views = // ...
    views.forEach {Zview -> /* ... */ }1
    views.forEachIndexed { index, view -> /* ... */ }1
    ViewGroups.kt
    inline fun ViewGroup.forEach(action: (View) -> Unit) {
    for (index in 0 until childCount) {
    action(getChildAt(index))
    }2
    }3
    inline fun ViewGroup.forEachIndexed(action: (Int, View) -> Unit) {
    for (index in 0 until childCount) {
    action(index, getChildAt(index))
    }
    }
    /
    / T
    O
    D
    O d
    o s
    o
    m
    e
    t
    h
    i
    n
    g w
    i
    t
    h v
    i
    e
    w

    View Slide

  32. MainActivity.kt
    val views = // ...
    /
    / T
    O
    D
    O d
    o s
    o
    m
    e
    t
    h
    i
    n
    g w
    i
    t
    h v
    i
    e
    w
    ViewGroups.kt
    operator fun ViewGroup.get(index: Int): View? = getChildAt(index)

    View Slide

  33. MainActivity.kt
    val views = // ...
    val first = views[0]
    ViewGroups.kt
    operator fun ViewGroup.get(index: Int): View? = getChildAt(index)
    /
    / T
    O
    D
    O d
    o s
    o
    m
    e
    t
    h
    i
    n
    g w
    i
    t
    h v
    i
    e
    w

    View Slide

  34. MainActivity.kt
    val views = // ...
    val first = views[0]
    ViewGroups.kt
    operator fun ViewGroup.get(index: Int): View? = getChildAt(index)
    /
    / T
    O
    D
    O d
    o s
    o
    m
    e
    t
    h
    i
    n
    g w
    i
    t
    h v
    i
    e
    w

    View Slide

  35. MainActivity.kt
    val views = // ...
    val first = views[0]
    ViewGroups.kt
    operator fun ViewGroup.get(index: Int): View? = getChildAt(index)
    /
    / T
    O
    D
    O d
    o s
    o
    m
    e
    t
    h
    i
    n
    g w
    i
    t
    h v
    i
    e
    w

    View Slide

  36. MainActivity.kt
    val views = // ...
    val first = views[0]
    views -= first
    ViewGroups.kt
    operator fun ViewGroup.get(index: Int): View? = getChildAt(index)
    operator fun ViewGroup.minusAssign(child: View) = removeView(child)
    /
    / T
    O
    D
    O d
    o s
    o
    m
    e
    t
    h
    i
    n
    g w
    i
    t
    h v
    i
    e
    w

    View Slide

  37. MainActivity.kt
    val views = // ...
    val first = views[0]
    views -= first
    ViewGroups.kt
    operator fun ViewGroup.get(index: Int): View? = getChildAt(index)
    operator fun ViewGroup.minusAssign(child: View) = removeView(child)
    /
    / T
    O
    D
    O d
    o s
    o
    m
    e
    t
    h
    i
    n
    g w
    i
    t
    h v
    i
    e
    w

    View Slide

  38. MainActivity.kt
    val views = // ...
    val first = views[0]
    views -= first
    views += first
    ViewGroups.kt
    operator fun ViewGroup.get(index: Int): View? = getChildAt(index)
    operator fun ViewGroup.minusAssign(child: View) = removeView(child)
    operator fun ViewGroup.plusAssign(child: View) = addView(child)
    /
    / T
    O
    D
    O d
    o s
    o
    m
    e
    t
    h
    i
    n
    g w
    i
    t
    h v
    i
    e
    w

    View Slide

  39. MainActivity.kt
    val views = // ...
    val first = views[0]
    views -= first
    views += first
    ViewGroups.kt
    operator fun ViewGroup.get(index: Int): View? = getChildAt(index)
    operator fun ViewGroup.minusAssign(child: View) = removeView(child)
    operator fun ViewGroup.plusAssign(child: View) = addView(child)
    /
    / T
    O
    D
    O d
    o s
    o
    m
    e
    t
    h
    i
    n
    g w
    i
    t
    h v
    i
    e
    w

    View Slide

  40. MainActivity.kt
    val views = // ...
    val first = views[0]
    views -= first
    views += first
    if (first in views) doSomething()
    ViewGroups.kt
    operator fun ViewGroup.get(index: Int): View? = getChildAt(index)
    operator fun ViewGroup.minusAssign(child: View) = removeView(child)
    operator fun ViewGroup.plusAssign(child: View) = addView(child)
    operator fun ViewGroup.contains(child: View) = indexOfChild(child) != -1
    /
    / T
    O
    D
    O d
    o s
    o
    m
    e
    t
    h
    i
    n
    g w
    i
    t
    h v
    i
    e
    w

    View Slide

  41. MainActivity.kt
    val views = // ...
    val first = views[0]
    views -= first
    views += first
    if (first in views) doSomething()
    ViewGroups.kt
    operator fun ViewGroup.get(index: Int): View? = getChildAt(index)
    operator fun ViewGroup.minusAssign(child: View) = removeView(child)
    operator fun ViewGroup.plusAssign(child: View) = addView(child)
    operator fun ViewGroup.contains(child: View) = indexOfChild(child) != -1
    /
    / T
    O
    D
    O d
    o s
    o
    m
    e
    t
    h
    i
    n
    g w
    i
    t
    h v
    i
    e
    w

    View Slide

  42. MainActivity.kt
    val views = // ...
    val first = views[0]
    views -= first
    views += first
    if (first in views) doSomething()
    ViewGroups.kt
    operator fun ViewGroup.get(index: Int): View? = getChildAt(index)
    operator fun ViewGroup.minusAssign(child: View) = removeView(child)
    operator fun ViewGroup.plusAssign(child: View) = addView(child)
    operator fun ViewGroup.contains(child: View) = indexOfChild(child) != -1
    /
    / T
    O
    D
    O d
    o s
    o
    m
    e
    t
    h
    i
    n
    g w
    i
    t
    h v
    i
    e
    w

    View Slide

  43. MainActivity.kt
    val views = // ...
    val first = views[0]
    views -= first
    views += first
    if (first in views) doSomething()
    ViewGroups.kt
    operator fun ViewGroup.get(index: Int): View? = getChildAt(index)
    operator fun ViewGroup.minusAssign(child: View) = removeView(child)
    operator fun ViewGroup.plusAssign(child: View) = addView(child)
    operator fun ViewGroup.contains(child: View) = indexOfChild(child) != -1
    /
    / T
    O
    D
    O d
    o s
    o
    m
    e
    t
    h
    i
    n
    g w
    i
    t
    h v
    i
    e
    w

    View Slide

  44. MainActivity.kt
    val views = // ...
    val first = views[0]
    views -= first
    views += first
    if (first in views) doSomething()
    ViewGroups.kt
    operator fun ViewGroup.get(index: Int): View? = getChildAt(index)
    operator fun ViewGroup.minusAssign(child: View) = removeView(child)
    operator fun ViewGroup.plusAssign(child: View) = addView(child)
    operator fun ViewGroup.contains(child: View) = indexOfChild(child) != -1
    /
    / T
    O
    D
    O d
    o s
    o
    m
    e
    t
    h
    i
    n
    g w
    i
    t
    h v
    i
    e
    w

    View Slide

  45. MainActivity.kt
    val views = // ...
    val first = views.get(0)
    views.minusAssign(first)
    views.plusAssign(first)
    if (views.contains(first)) doSomething()
    ViewGroups.kt
    operator fun ViewGroup.get(index: Int): View? = getChildAt(index)
    operator fun ViewGroup.minusAssign(child: View) = removeView(child)
    operator fun ViewGroup.plusAssign(child: View) = addView(child)
    operator fun ViewGroup.contains(child: View) = indexOfChild(child) != -1
    /
    / T
    O
    D
    O d
    o s
    o
    m
    e
    t
    h
    i
    n
    g w
    i
    t
    h v
    i
    e
    w
    in

    View Slide

  46. MainActivity.kt
    val views = // ...
    val first = views[0]
    views -= first
    views += first
    if (first in views) doSomething()
    ViewGroups.kt
    operator fun ViewGroup.get(index: Int): View? = getChildAt(index)
    operator fun ViewGroup.minusAssign(child: View) = removeView(child)
    operator fun ViewGroup.plusAssign(child: View) = addView(child)
    operator fun ViewGroup.contains(child: View) = indexOfChild(child) != -1
    /
    / T
    O
    D
    O d
    o s
    o
    m
    e
    t
    h
    i
    n
    g w
    i
    t
    h v
    i
    e
    w

    View Slide

  47. MainActivity.kt
    val views = // ...
    val first = views[0]
    views -= first
    views += first
    if (first in views) doSomething()
    Log.d("MainActivity", "View count: ${views.size}")
    ViewGroups.kt
    operator fun ViewGroup.get(index: Int): View? = getChildAt(index)
    operator fun ViewGroup.minusAssign(child: View) = removeView(child)
    operator fun ViewGroup.plusAssign(child: View) = addView(child)
    operator fun ViewGroup.contains(child: View) = indexOfChild(child) != -1
    val ViewGroup.size: Int
    get() = childCount
    /
    / T
    O
    D
    O d
    o s
    o
    m
    e
    t
    h
    i
    n
    g w
    i
    t
    h v
    i
    e
    w

    View Slide

  48. MainActivity.kt
    val views = // ...
    val first = views[0]
    views -= first
    views += first
    if (first in views) doSomething()
    Log.d("MainActivity", "View count: ${views.size}")
    ViewGroups.kt
    operator fun ViewGroup.get(index: Int): View? = getChildAt(index)
    operator fun ViewGroup.minusAssign(child: View) = removeView(child)
    operator fun ViewGroup.plusAssign(child: View) = addView(child)
    operator fun ViewGroup.contains(child: View) = indexOfChild(child) != -1
    val ViewGroup.size: Int
    get() = childCount
    /
    / T
    O
    D
    O d
    o s
    o
    m
    e
    t
    h
    i
    n
    g w
    i
    t
    h v
    i
    e
    w

    View Slide

  49. MainActivity.kt
    val views = // ...
    val first = views[0]
    views -= first
    views += first
    if (first in views) doSomething()
    Log.d("MainActivity", "View count: ${views.size}")
    ViewGroups.kt
    operator fun ViewGroup.get(index: Int): View? = getChildAt(index)
    operator fun ViewGroup.minusAssign(child: View) = removeView(child)
    operator fun ViewGroup.plusAssign(child: View) = addView(child)
    operator fun ViewGroup.contains(child: View) = indexOfChild(child) != -1
    val ViewGroup.size: Int
    get() = childCount
    /
    / T
    O
    D
    O d
    o s
    o
    m
    e
    t
    h
    i
    n
    g w
    i
    t
    h v
    i
    e
    w

    View Slide

  50. MainActivity.kt
    val views = // ...
    val first = views[0]
    views -= first
    views += first
    if (first in views) doSomething()
    Log.d("MainActivity", "View count: ${views.size}")
    ViewGroups.kt
    operator fun ViewGroup.get(index: Int): View? = getChildAt(index)
    operator fun ViewGroup.minusAssign(child: View) = removeView(child)
    operator fun ViewGroup.plusAssign(child: View) = addView(child)
    operator fun ViewGroup.contains(child: View) = indexOfChild(child) != -1
    val ViewGroup.size: Int
    get() = childCount
    /
    / T
    O
    D
    O d
    o s
    o
    m
    e
    t
    h
    i
    n
    g w
    i
    t
    h v
    i
    e
    w

    View Slide

  51. MainActivity.kt
    val views = // ...
    val first = views[0]
    views -= first
    views += first
    if (first in views) doSomething()
    Log.d("MainActivity", "View count: ${views.size}")
    ViewGroups.kt
    operator fun ViewGroup.get(index: Int): View? = getChildAt(index)
    operator fun ViewGroup.minusAssign(child: View) = removeView(child)
    operator fun ViewGroup.plusAssign(child: View) = addView(child)
    operator fun ViewGroup.contains(child: View) = indexOfChild(child) != -1
    val ViewGroup.size: Int
    get() = childCount
    /
    / T
    O
    D
    O d
    o s
    o
    m
    e
    t
    h
    i
    n
    g w
    i
    t
    h v
    i
    e
    w

    View Slide

  52. MainActivity.kt
    val views = // ...
    /
    / T
    O
    D
    O d
    o s
    o
    m
    e
    t
    h
    i
    n
    g w
    i
    t
    h v
    i
    e
    w
    ViewGroups.kt
    fun ViewGroup.children() = object : Iterable {
    override fun iterator() = object : Iterator {
    var index = 0
    override fun hasNext() = index < childCount
    override fun next() = getChildAt(index++)
    }
    }

    View Slide

  53. MainActivity.kt
    val views = // ...
    for (view in views.children()) {
    // TODO do something with view
    }1
    ViewGroups.kt
    fun ViewGroup.children() = object : Iterable {
    override fun iterator() = object : Iterator {
    var index = 0
    override fun hasNext() = index < childCount
    override fun next() = getChildAt(index++)
    }2
    }3
    /
    / T
    O
    D
    O d
    o s
    o
    m
    e
    t
    h
    i
    n
    g w
    i
    t
    h v
    i
    e
    w

    View Slide

  54. MainActivity.kt
    val views = // ...
    for (view in views.children()) {
    // TODO do something with view
    }1
    val visibleHeight = views.children()
    .filter { it.visibility == View.VISIBLE }
    .sumBy { it.measuredHeight }
    ViewGroups.kt
    fun ViewGroup.children() = object : Iterable {
    override fun iterator() = object : Iterator {
    var index = 0
    override fun hasNext() = index < childCount
    override fun next() = getChildAt(index++)
    }2
    }3
    /
    / T
    O
    D
    O d
    o s
    o
    m
    e
    t
    h
    i
    n
    g w
    i
    t
    h v
    i
    e
    w

    View Slide

  55. MainActivity.kt
    val views = // ...
    for (view in views.children()) {
    // TODO do something with view
    }
    val visibleHeight = views.children()
    .filter { it.visibility == View.VISIBLE }
    .sumBy { it.measuredHeight }
    ViewGroups.kt
    fun ViewGroup.children() = object : Iterable {
    override fun iterator() = object : Iterator {
    var index = 0
    override fun hasNext() = index < childCount
    override fun next() = getChildAt(index++)
    }
    }
    /
    / T
    O
    D
    O d
    o s
    o
    m
    e
    t
    h
    i
    n
    g w
    i
    t
    h v
    i
    e
    w

    View Slide

  56. MainActivity.java
    Trace.beginSection(sectionName);
    expensiveCalculation();
    Trace.endSection();

    View Slide

  57. MainActivity.java
    Trace.beginSection(sectionName);
    expensiveCalculation();
    Trace.endSection();
    Traces.kt
    inline fun trace(sectionName: String, body: () -> Unit) {
    Trace.beginSection(sectionName)
    try {
    body()
    }2finally {
    Trace.endSection()
    }3
    }4

    View Slide

  58. Traces.kt
    inline fun trace(sectionName: String, body: () -> Unit) {Z
    Trace.beginSection(sectionName)
    try {
    body()
    }2finally {
    Trace.endSection()
    }3
    }4
    MainActivity.kt
    trace("foo") {
    expensiveCalculation()
    }1

    View Slide

  59. Traces.kt
    inline fun trace(sectionName: String, body: () -> T): T {Z
    Trace.beginSection(sectionName)
    try {
    return body()
    }2finally {
    Trace.endSection()
    }3
    }4
    Unit
    MainActivity.kt
    trace("foo") {
    expensiveCalculation()
    }1
    T T
    return

    View Slide

  60. Traces.kt
    inline fun trace(sectionName: String, body: () -> T): T {Z
    Trace.beginSection(sectionName)
    try {
    return body()
    }2finally {
    Trace.endSection()
    }3
    }4
    MainActivity.kt
    val result = trace("foo") {
    expensiveCalculation()
    }1
    val result =
    T T
    return

    View Slide

  61. Traces.kt
    inline fun trace(sectionName: String, body: () -> T): T {Z
    Trace.beginSection(sectionName)
    try {
    return body()
    }2finally {
    Trace.endSection()
    }3
    }4
    MainActivity.kt
    val result = trace("foo") {
    expensiveCalculation()
    }1

    View Slide

  62. MainActivity.java
    SQLiteDatabase db = // ...
    db.beginTransaction();
    try {
    db.delete("users", "first_name = ?", new String[] { "jake" });
    } finally {
    db.endTransaction();
    }1

    View Slide

  63. MainActivity.java
    SQLiteDatabase db = // ...
    db.beginTransaction();
    try {
    db.delete("users", "first_name = ?", new String[] { "jake" });
    db.setTransactionSuccessful();
    } finally {
    db.endTransaction();
    }1

    View Slide

  64. SQLiteDatabase db = // ...
    db.beginTransaction();
    try {
    db.delete("users", "first_name = ?", new String[] { "jake" });
    db.setTransactionSuccessful();
    } finally {
    db.endTransaction();
    }1
    Databases.kt
    inline fun SQLiteDatabase.transaction(body: () -> Unit) {
    beginTransaction()
    try {
    body()
    setTransactionSuccessful()
    } finally {
    endTransaction()
    }2
    }1

    View Slide

  65. MainActivity.kt
    val db = // ...
    db.transaction {4
    db.delete("users", "first_name = ?", arrayOf("jake"))
    }3
    Databases.kt
    inline fun SQLiteDatabase.transaction(body: () -> Unit) {
    beginTransaction()
    try {
    body()X
    setTransactionSuccessful()
    } finally {
    endTransaction()
    }2
    }1 1
    SQLiteDatabase
    db.beginTransaction();
    try
    new String[] { }
    db.setTransactionSuccessful();
    finally {
    db.endTransaction();
    }1

    View Slide

  66. MainActivity.kt
    val db = // ...
    db.transaction {4
    db.delete("users", "first_name = ?", arrayOf("jake"))
    }3
    Databases.kt
    inline fun SQLiteDatabase.transaction(body: () -> Unit) {
    beginTransaction()
    try {
    body()X
    setTransactionSuccessful()
    } finally {
    endTransaction()
    }2
    }1 1

    View Slide

  67. MainActivity.kt
    val db = // ...
    db.transaction {4
    db.delete("users", "first_name = ?", arrayOf("jake"))
    }3
    Databases.kt
    inline fun SQLiteDatabase.transaction(body: () -> Unit) {
    beginTransaction()
    try {
    body()X
    setTransactionSuccessful()
    } finally {
    endTransaction()
    }2
    }1 1

    View Slide

  68. MainActivity.kt
    val db = // ...
    db.transaction {4
    db.delete("users", "first_name = ?", arrayOf("jake"))
    }3
    Databases.kt
    inline fun SQLiteDatabase.transaction(body: (SQLiteDatabase) -> Unit) {
    beginTransaction()
    try {
    body()X
    setTransactionSuccessful()
    } finally {
    endTransaction()
    }2
    }1 1
    SQLiteDatabase

    View Slide

  69. MainActivity.kt
    val db = // ...
    db.transaction {4
    db.delete("users", "first_name = ?", arrayOf("jake"))
    }3
    Databases.kt
    inline fun SQLiteDatabase.transaction(body: (SQLiteDatabase) -> Unit) {
    beginTransaction()
    try {
    body(this)X
    setTransactionSuccessful()
    } finally {
    endTransaction()
    }2
    }1 1
    SQLiteDatabase
    body(this)X

    View Slide

  70. MainActivity.kt
    val db = // ...
    db.transaction {4
    it.delete("users", "first_name = ?", arrayOf("jake"))
    }3
    Databases.kt
    inline fun SQLiteDatabase.transaction(body: (SQLiteDatabase) -> Unit) {
    beginTransaction()
    try {
    body(this)
    setTransactionSuccessful()
    } finally {
    endTransaction()
    }2
    }1 1
    it.delete
    SQLiteDatabase
    body(this)X

    View Slide

  71. MainActivity.kt
    val db = // ...
    db.transaction {4
    it.delete("users", "first_name = ?", arrayOf("jake"))
    }3
    Databases.kt
    inline fun SQLiteDatabase.transaction(body: (SQLiteDatabase) -> Unit) {
    beginTransaction()
    try {
    body(this)F
    setTransactionSuccessful()
    } finally {
    endTransaction()
    }2
    }1 1

    View Slide

  72. MainActivity.kt
    val db = // ...
    db.transaction {4
    it.delete("users", "first_name = ?", arrayOf("jake"))
    }3
    Databases.kt
    inline fun SQLiteDatabase.transaction(body: (SQLiteDatabase) -> Unit) {
    beginTransaction()
    try {
    body(this)F
    setTransactionSuccessful()
    } finally {
    endTransaction()
    }2
    }1 1

    View Slide

  73. MainActivity.kt
    val db = // ...
    db.transaction {4
    it.delete("users", "first_name = ?", arrayOf("jake"))
    }3
    Databases.kt
    inline fun SQLiteDatabase.transaction(body: (SQLiteDatabase) -> Unit) {
    beginTransaction()
    try {
    body(this)F
    setTransactionSuccessful()
    } finally {
    endTransaction()
    }2
    }1 1

    View Slide

  74. MainActivity.kt
    val db = // ...
    db.transaction {4
    it.delete("users", "first_name = ?", arrayOf("jake"))
    }3
    Databases.kt
    inline fun SQLiteDatabase.transaction(body: SQLiteDatabase.() -> Unit) {
    beginTransaction()
    try {
    body(this)F
    setTransactionSuccessful()
    } finally {
    endTransaction()
    }2
    }1 1
    SQLiteDatabase.() -> Unit

    View Slide

  75. MainActivity.kt
    val db = // ...
    db.transaction {4
    it.delete("users", "first_name = ?", arrayOf("jake"))
    }3
    Databases.kt
    inline fun SQLiteDatabase.transaction(body: SQLiteDatabase.() -> Unit) {
    beginTransaction()
    try {
    body()
    setTransactionSuccessful()
    } finally {
    endTransaction()
    }2
    }1 1
    SQLiteDatabase.() -> Unit
    body()F

    View Slide

  76. it.
    MainActivity.kt
    val db = // ...
    db.transaction {4
    delete("users", "first_name = ?", arrayOf("jake"))
    }3
    Databases.kt
    inline fun SQLiteDatabase.transaction(body: SQLiteDatabase.() -> Unit) {
    beginTransaction()
    try {
    body()
    setTransactionSuccessful()
    } finally {
    endTransaction()
    }2
    }1 1
    delete
    SQLiteDatabase.() -> Unit
    body()F

    View Slide

  77. MainActivity.kt
    val db = // ...
    db.transaction {4
    delete("users", "first_name = ?", arrayOf("jake"))G
    }3
    Databases.kt
    inline fun SQLiteDatabase.transaction(body: SQLiteDatabase.() -> Unit) {
    beginTransaction()
    try {
    body()
    setTransactionSuccessful()
    } finally {
    endTransaction()
    }2
    }1 1

    View Slide

  78. MainActivity.kt
    = // ...
    "jake"
    Databases.kt
    inline fun SQLiteDatabase.transaction(body: SQLiteDatabase.() -> Unit) {
    beginTransaction()
    try {
    body()
    setTransactionSuccessful()
    } finally {
    endTransaction()
    }2
    }1 1
    class UserPersistence(private val db: SQLiteDatabase) {
    fun deleteByFirstName(name: String) {
    db.transaction {
    delete("users", "first_name = ?", arrayOf(name))G
    }3
    }
    }
    UserPersistence.kt

    View Slide

  79. MainActivity.kt
    = // ...
    "jake"
    Databases.kt
    inline fun SQLiteDatabase.transaction(body: SQLiteDatabase.() -> Unit) {
    beginTransaction()
    try {
    body()
    setTransactionSuccessful()
    } finally {
    endTransaction()
    }2
    }1 1
    class UserPersistence(private val db: SQLiteDatabase) {
    fun deleteByFirstName(name: String) {
    db.transaction {
    delete("users", "first_name = ?", arrayOf(name))G
    }3
    }
    }
    UserPersistence.kt

    View Slide

  80. class UserPersistence(private val db: SQLiteDatabase) {
    fun deleteByFirstName(name: String) {
    db.transaction {
    delete("users", "first_name = ?", arrayOf(name))G
    }3
    }2
    }1
    UserPersistence.kt

    View Slide

  81. class UserPersistence(private val db: SQLiteDatabase) {
    private val deleteByFirstName = db.compileStatement(
    "DELETE FROM users WHERE first_name = ?")
    fun deleteByFirstName(name: String) {
    db.transaction {
    deleteByFirstName.bindString(1, name)
    deleteByFirstName.execute()
    }3
    }2
    }1
    UserPersistence.kt
    delete(" ", " , arrayOf( ))G

    View Slide

  82. sssssssssssss
    class UserPersistence(private val db: SQLiteDatabase) {
    private val deleteByFirstName = db.compileStatement(
    "DELETE FROM users WHERE first_name = ?")
    fun deleteByFirstName(name: String) {
    db.transaction {
    deleteByFirstName.bindString(1, name)
    deleteByFirstName.execute()
    }3
    }2
    }1
    UserPersistence.kt

    View Slide

  83. sssssssssssss
    class UserPersistence(private val db: SQLiteDatabase) {
    private val deleteByFirstName by lazy {
    db.compileStatement("DELETE FROM users WHERE first_name = ?")
    }
    fun deleteByFirstName(name: String) {
    db.transaction {
    deleteByFirstName.bindString(1, name)
    deleteByFirstName.execute()
    }3
    }2
    }1
    UserPersistence.kt

    View Slide

  84. sssssssssssss
    class UserPersistence(private val db: SQLiteDatabase) {
    private val deleteByFirstName by lazy {
    db.compileStatement("DELETE FROM users WHERE first_name = ?")
    }X
    fun deleteByFirstName(name: String) {
    db.transaction {
    deleteByFirstName.bindString(1, name)
    deleteByFirstName.execute()
    }3
    }2
    }1
    UserPersistence.kt

    View Slide

  85. private val deleteByFirstName by lazy {
    db.compileStatement("DELETE FROM users WHERE first_name = ?")
    }X

    View Slide

  86. private val deleteByFirstName by lazy {
    db.compileStatement("DELETE FROM users WHERE first_name = ?")
    }X
    private val name by Delegates.observable("jane") { old, new, prop ->
    println("Name changed from $old to $new")
    }

    View Slide

  87. private val deleteByFirstName by lazy {
    db.compileStatement("DELETE FROM users WHERE first_name = ?")
    }X
    private val name by Delegates.observable("jane") { old, new, prop ->
    println("Name changed from $old to $new")
    }
    private val address by Delegates.notNull()

    View Slide

  88. private val deleteByFirstName by lazy {
    db.compileStatement("DELETE FROM users WHERE first_name = ?")
    }X
    private val name by Delegates.observable("jane") { old, new, prop ->
    println("Name changed from $old to $new")
    }
    private val address by Delegates.notNull()
    private val nameView by bindView(R.id.name)

    View Slide

  89. private val deleteByFirstName by lazy {
    db.compileStatement("DELETE FROM users WHERE first_name = ?")
    }X
    private val name by Delegates.observable("jane") { old, new, prop ->
    println("Name changed from $old to $new")
    }
    private val address by Delegates.notNull()
    private val nameView by bindView(R.id.name)

    View Slide

  90. class MyListener : TransitionListener {
    override fun onTransitionEnd(transition: Transition) {
    }
    override fun onTransitionResume(transition: Transition) {
    }
    override fun onTransitionPause(transition: Transition) {
    }
    override fun onTransitionCancel(transition: Transition) {
    }
    override fun onTransitionStart(transition: Transition) {
    }Y
    }X

    View Slide

  91. class MyListener : TransitionListener {
    override fun onTransitionStart(transition: Transition) {
    }Y
    }X

    View Slide

  92. class MyListener : TransitionListener {
    override fun onTransitionStart(transition: Transition) {
    }Y
    }X
    object EmptyTransitionListener : TransitionListener {
    override fun onTransitionEnd(transition: Transition) {}
    override fun onTransitionResume(transition: Transition) {}
    override fun onTransitionPause(transition: Transition) {}
    override fun onTransitionCancel(transition: Transition) {}
    override fun onTransitionStart(transition: Transition) {}
    }

    View Slide

  93. class MyListener : TransitionListener {
    override fun onTransitionStart(transition: Transition) {
    }Y
    }X
    object EmptyTransitionListener : TransitionListener {
    override fun onTransitionEnd(transition: Transition) {}
    override fun onTransitionResume(transition: Transition) {}
    override fun onTransitionPause(transition: Transition) {}
    override fun onTransitionCancel(transition: Transition) {}
    override fun onTransitionStart(transition: Transition) {}
    }

    View Slide

  94. class MyListener : TransitionListener {T
    override fun onTransitionStart(transition: Transition) {
    }Y
    }X
    object EmptyTransitionListener : TransitionListener {
    override fun onTransitionEnd(transition: Transition) {}
    override fun onTransitionResume(transition: Transition) {}
    override fun onTransitionPause(transition: Transition) {}
    override fun onTransitionCancel(transition: Transition) {}
    override fun onTransitionStart(transition: Transition) {}
    }G

    View Slide

  95. class MyListener : TransitionListener by EmptyTransitionListener {T
    override fun onTransitionStart(transition: Transition) {
    }Y
    }X
    object EmptyTransitionListener : TransitionListener {
    override fun onTransitionEnd(transition: Transition) {}
    override fun onTransitionResume(transition: Transition) {}
    override fun onTransitionPause(transition: Transition) {}
    override fun onTransitionCancel(transition: Transition) {}
    override fun onTransitionStart(transition: Transition) {}
    }G

    View Slide

  96. class MyListener : TransitionListener by EmptyTransitionListener {T
    override fun onTransitionStart(transition: Transition) {
    }Y
    }X
    object EmptyTransitionListener : TransitionListener {
    override fun onTransitionEnd(transition: Transition) {}
    override fun onTransitionResume(transition: Transition) {}
    override fun onTransitionPause(transition: Transition) {}
    override fun onTransitionCancel(transition: Transition) {}
    override fun onTransitionStart(transition: Transition) {}
    }G

    View Slide

  97. class PaymentRobot {
    fun amount(value: Long) {
    // TODO Espresso interactions
    }
    fun recipient(value: String) {
    // TODO Espresso interactions
    }
    fun send() {
    // TODO Espresso interactions
    }
    }
    PaymentRobot.kt

    View Slide

  98. @Test fun sendMoney() {
    PaymentRobot().apply {
    amount(4_00)
    recipient("[email protected]")
    send()
    }
    }
    PaymentTest.kt

    View Slide

  99. class PaymentRobot {
    fun amount(value: Long) {
    // TODO Espresso interactions
    }
    fun recipient(value: String) {
    // TODO Espresso interactions
    }
    fun send() {
    // TODO Espresso interactions
    }
    }
    PaymentRobot.kt

    View Slide

  100. class PaymentRobot {
    fun amount(value: Long) {
    // TODO Espresso interactions
    }
    fun recipient(value: String) {
    // TODO Espresso interactions
    }
    fun send() {
    // TODO Espresso interactions
    }
    }
    PaymentRobot.kt
    fun payment(body: PaymentRobot.() -> Unit) = PaymentRobot().apply(body)

    View Slide

  101. class PaymentRobot {
    fun amount(value: Long) {
    // TODO Espresso interactions
    }
    fun recipient(value: String) {
    // TODO Espresso interactions
    }
    fun send() {
    // TODO Espresso interactions
    }
    }
    PaymentRobot.kt
    fun payment(body: PaymentRobot.() -> Unit) = PaymentRobot().apply(body)

    View Slide

  102. @Test fun sendMoney() {
    PaymentRobot().apply {T
    amount(4_00)
    recipient("[email protected]")
    send()
    }T
    }G
    PaymentTest.kt
    p

    View Slide

  103. @Test fun sendMoney() {
    payment {T
    amount(4_00)
    recipient("[email protected]")
    send()
    }T
    }G
    PaymentTest.kt

    View Slide

  104. sealed class Payloads {
    }G

    View Slide

  105. sealed class Payloads {
    data class Favorite(val favorited: Boolean) : Payloads()
    }G

    View Slide

  106. sealed class Payloads {
    data class Favorite(val favorited: Boolean) : Payloads()
    data class Retweet(val retweeted: Boolean) : Payloads()
    }G

    View Slide

  107. sealed class Payloads {
    data class Favorite(val favorited: Boolean) : Payloads()
    data class Retweet(val retweeted: Boolean) : Payloads()
    data class CountUpdate(
    val favorites: Long,
    val retweets: Long,
    val replies: Long) : Payloads()
    }G

    View Slide

  108. override fun onBindViewHolder(holder: TweetViewHolder,
    position: Int, payloads: List) {
    }1

    View Slide

  109. override fun onBindViewHolder(holder: TweetViewHolder,
    position: Int, payloads: List) {
    payloads.forEach {
    }2
    }1

    View Slide

  110. override fun onBindViewHolder(holder: TweetViewHolder,
    position: Int, payloads: List) {
    payloads.forEach {
    when (it) {
    }3
    }2
    }1

    View Slide

  111. override fun onBindViewHolder(holder: TweetViewHolder,
    position: Int, payloads: List) {
    payloads.forEach {
    when (it) {
    is Favorite -> holder.favoriteIcon.isActivated = it.favorited
    }3
    }2
    }1

    View Slide

  112. override fun onBindViewHolder(holder: TweetViewHolder,
    position: Int, payloads: List) {
    payloads.forEach {
    when (it) {
    is Favorite -> holder.favoriteIcon.isActivated = it.favorited
    }3
    }2
    }1

    View Slide

  113. override fun onBindViewHolder(holder: TweetViewHolder,
    position: Int, payloads: List) {
    payloads.forEach {
    when (it) {
    is Favorite -> holder.favoriteIcon.isActivated = it.favorited
    }3
    }2
    }1
    sealed class Payloads {
    data class Favorite(val favorited: Boolean) : Payloads()
    data class Retweet(val retweeted: Boolean) : Payloads()
    data class CountUpdate(
    val favorites: Long,
    val retweets: Long,
    val replies: Long) : Payloads()
    }G

    View Slide

  114. override fun onBindViewHolder(holder: TweetViewHolder,
    position: Int, payloads: List) {
    payloads.forEach {
    when (it) {
    is Favorite -> holder.favoriteIcon.isActivated = it.favorited
    }3
    }2
    }1

    View Slide

  115. override fun onBindViewHolder(holder: TweetViewHolder,
    position: Int, payloads: List) {
    payloads.forEach {
    when (it) {
    is Favorite -> holder.favoriteIcon.isActivated = it.favorited
    is Retweet -> holder.retweetIcon.isActivated = it.retweeted
    }3
    }2
    }1

    View Slide

  116. override fun onBindViewHolder(holder: TweetViewHolder,
    position: Int, payloads: List) {
    payloads.forEach {
    when (it) {
    is Favorite -> holder.favoriteIcon.isActivated = it.favorited
    is Retweet -> holder.retweetIcon.isActivated = it.retweeted
    is CountUpdate -> {
    holder.apply {
    favoriteCount.text = it.favorites.toString()
    retweetCount.text = it.retweets.toString()
    replyCount.text = it.replies.toString()
    }5
    }4
    }3
    }2
    }1

    View Slide

  117. View Slide

  118. It takes great salesmanship to
    convince a customer to buy
    something from you that isn't
    built or isn't finished.
    Fred Wilson

    View Slide

  119. View Slide

  120. View Slide

  121. Step 3
    Step 2
    Step 1

    View Slide

  122. Step 1 Step 3
    You
    Step 2

    View Slide

  123. Step 3
    Management
    Step 2
    Step 1

    View Slide

  124. Team
    Step 3
    Step 2
    Step 1

    View Slide

  125. You
    Get excited.

    View Slide

  126. Never doubt that a
    small group of
    thoughtful, committed
    citizens can change
    the world; indeed,

    it's the only thing 

    that ever has.
    Margaret Mead (Def. not talking about tech)

    View Slide

  127. Be enthusiastic

    View Slide

  128. Adoption is work. If you want it, you need to earn it.

    View Slide

  129. Management
    Be persuasive.

    View Slide

  130. I call it my billion-
    dollar mistake.
    Sir Charles Antony Richard Hoare

    View Slide

  131. One of the most feared
    expressions in modern
    times is 'The computer
    is down.'
    Norman Ralph Augustine

    View Slide

  132. View Slide

  133. Jake Wharton
    @JakeWharton
    Type systems are a form of tests. I declare an expected
    type and the tests (aka compiler) validates the actual ones.
    6:43 PM - 11 Jan 2017
    74
    Follow
    16

    View Slide

  134. View Slide

  135. Team
    Do the work.

    View Slide

  136. Ellen Shapiro @designatednerd
    My style: “I’m the idiot who went down the rabbit hole first,
    and I’m here to tell you which path leads to fluffy bunnies vs.
    angry moles.”
    14 Mar
    Ellen Shapiro
    @designatednerd
    My favorite bit of any talk I give is talking about the dumb
    shit I did so the audience doesn’t do it. Makes the hair
    pulled out worth it.
    4:56 PM - 14 Mar 2017
    1
    Follow

    View Slide

  137. Define success

    View Slide

  138. View Slide

  139. View Slide

  140. http://blog.danlew.net/

    View Slide

  141. On-boarding
    should be a first
    class citizen

    View Slide

  142. Show up

    View Slide

  143. View Slide

  144. What’s next?
    Kotlin documentation and koans
    https://kotlinlang.org/
    Android Kotlin documentation
    https://developer.android.com/kotlin/index.html
    Kotlin In Action
    Dimitry Jemerov, Svetlana Isakova

    View Slide

  145. +Christina Lee
    @RunChristinaRun
    #KotlinIsHere
    Thank you!
    +Jake Wharton
    @JakeWharton

    View Slide

  146. View Slide