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

Android Development with Kotlin (AndroidKW #001)

Android Development with Kotlin (AndroidKW #001)

Using Kotlin for Android development has grown in popularity over the last year. Even to those who are not currently using it, the value proposition of the language immediately resonates. There already are a lot of introductory talks to the language and its extensions for use on Android. This talk will cover advancing the usage and design patterns of the language for Android development to solve larger problems. While the content is targeted at mobile development, there will be value for all Java developers interested in Kotlin.

Prior knowledge or use of Kotlin is not required to attend this talk. Some concepts of the language will be used without introduction but they are intuitive and/or quickly learned. Even if you don't fully understand every language concept on which each example is built, the resulting functionality will be clear.

Presented at http://www.meetup.com/androidkw/events/226683586/

Video: http://youtu.be/A2LukgT2mKc

Jake Wharton

December 03, 2015
Tweet

More Decks by Jake Wharton

Other Decks in Programming

Transcript

  1. Why do we need Kotlin? • Stuck on Java 6(.5)ish

    • No javax.time • No streams
  2. Why do we need Kotlin? • Stuck on Java 6(.5)ish

    • No javax.time • No streams • No lambdas, method refs, non-capturing anon class
  3. Why do we need Kotlin? • Stuck on Java 6(.5)ish

    • No javax.time • No streams • No lambdas, method refs, non-capturing anon class • No try-with-resources
  4. Why do we need Kotlin? • Stuck on Java 6(.5)ish

    • No javax.time Use ThreeTenBP / ThreeTenABP • No streams • No lambdas, method refs, non-capturing anon class • No try-with-resources
  5. Why do we need Kotlin? • Stuck on Java 6(.5)ish

    • No javax.time Use ThreeTenBP / ThreeTenABP • No streams Use backport or RxJava • No lambdas, method refs, non-capturing anon class • No try-with-resources
  6. Why do we need Kotlin? • Stuck on Java 6(.5)ish

    • No javax.time Use ThreeTenBP / ThreeTenABP • No streams Use backport or RxJava • No lambdas, method refs, non-capturing anon class Use Retrolambda • No try-with-resources
  7. Why do we need Kotlin? • Stuck on Java 6(.5)ish

    • No javax.time Use ThreeTenBP / ThreeTenABP • No streams Use backport or RxJava • No lambdas, method refs, non-capturing anon class Use Retrolambda • No try-with-resources minSdkVersion=19 or Retrolambda
  8. Why do we need Kotlin? • Stuck on Java 6(.5)ish

    • Java language restrictions and problems
  9. Why do we need Kotlin? • Java language restrictions and

    problems • Inability to add methods to platform types
  10. Why do we need Kotlin? • Java language restrictions and

    problems • Inability to add methods to platform types ("Util" hell)
  11. Why do we need Kotlin? • Java language restrictions and

    problems • Inability to add methods to platform types ("Util" hell) • Nullability problems
  12. Why do we need Kotlin? • Java language restrictions and

    problems • Inability to add methods to platform types ("Util" hell) • Nullability problems • Mutability problems
  13. Why do we need Kotlin? • Java language restrictions and

    problems • Inability to add methods to platform types ("Util" hell) • Nullability problems • Mutability problems • General verbosity of common idioms
  14. Why do we need Kotlin? • Stuck on Java 6(.5)ish

    • Java language restrictions and problems • Android API design problems
  15. Why do we need Kotlin? • Android API design problems

    • Inheritance party • Nullability everywhere
  16. Why do we need Kotlin? • Android API design problems

    • Inheritance party • Nullability everywhere • Ceremony of APIs
  17. Why do we need Kotlin? • Stuck on Java 6(.5)ish

    • Java language restrictions and problems • Android API design problems
  18. Extension Functions // com/example/util/DateExtensions.kt fun Date.isTuesday() = day == 2

    // com/example/TuesdayActivity.kt val tuesday = date.isTuesday()
  19. Extension Functions // com/example/util/DateExtensions.kt fun Date.isTuesday() = day == 2

    // com/example/TuesdayActivity.kt val tuesday = date.isTuesday()
  20. Extension Functions // com/example/util/DateExtensions.kt fun Date.isTuesday() = day == 2

    // com/example/TuesdayActivity.kt import com.example.util.isTuesday val tuesday = date.isTuesday()
  21. Extension Functions // com/example/util/DateExtensions.kt fun Date.isTuesday() = day == 2

    final static isTuesday(Ljava/util/Date;)Z L0 ALOAD 0 INVOKEVIRTUAL java/util/Date.getDay ()I ICONST_2 IF_ICMPNE L1 ICONST_1 GOTO L2 L1 ICONST_0 L2 IRETURN
  22. Extension Functions // com/example/util/DateExtensions.kt fun Date.isTuesday() = day == 2

    static boolean isTuesday(Date date) {
 return date.getDay() == 2;
 }X
  23. Extension Functions // com/example/util/DateExtensions.kt fun Date.isTuesday() = day == 2

    @file:JvmName("DateUtils") // com/example/util/DateExtensionsKt.java static boolean isTuesday(Date date) {
 return date.getDay() == 2;
 }X
  24. Extension Functions // com/example/util/DateExtensions.kt fun Date.isTuesday() = day == 2

    @file:JvmName("DateUtils") // com/example/util/DateUtils.java static boolean isTuesday(Date date) {
 return date.getDay() == 2;
 }X
  25. Extension Functions fun Date.getDay() = 2 fun View.isAttachedToWindow() = if

    (Build.VERSION.SDK_INT < 19) ViewCompat.isAttachedToWindow(this) else super.isAttachedToWindow()
  26. Extension Functions fun Date.getDay() = 2 fun View.isAttachedToWindowCompat() = if

    (Build.VERSION.SDK_INT < 19) ViewCompat.isAttachedToWindow(this) else isAttachedToWindow()
  27. Extension Functions String firstName1= null;
 int firstNameColumn = cursor.getColumnIndexOrThrow("first_name");
 if

    (!cursor.isNull(firstNameColumn)) {
 firstName3=2cursor.getString(firstNameColumn);
 }
  28. Extension Functions String firstName1= null;
 int firstNameColumn = cursor.getColumnIndexOrThrow("first_name");
 if

    (!cursor.isNull(firstNameColumn)) {
 firstName3=2cursor.getString(firstNameColumn);
 } fun Cursor.getStringOrNull(columnName: String): String? {
 val index = getColumnIndexOrThrow(columnName)
 return if (isNull(index)) null else getString(index)
 }X
 fun Cursor.getString(columnName: String): String = getStringOrNull(columnName)!!
  29. Extension Functions fun Cursor.getStringOrNull(columnName: String): String? {
 val index =

    getColumnIndexOrThrow(columnName)
 return if (isNull(index)) null else getString(index)
 }X
 fun Cursor.getString(columnName: String): String = getStringOrNull(columnName)!!
  30. Extension Functions fun Cursor.getStringOrNull(columnName: String): String? {
 val index =

    getColumnIndexOrThrow(columnName)
 return if (isNull(index)) null else getString(index)
 }X
 fun Cursor.getString(columnName: String): String = getStringOrNull(columnName)!! val firstName = cursor.getStringOrNull("first_name")
  31. Extension Functions fun Cursor.getStringOrNull(columnName: String): String? {
 val index =

    getColumnIndexOrThrow(columnName)
 return if (isNull(index)) null else getString(index)
 }X
 fun Cursor.getString(columnName: String): String = getStringOrNull(columnName)!! val firstName = cursor.getStringOrNull("first_name")
  32. Extension Functions fun Cursor.getStringOrNull(columnName: String): String? {
 val index =

    getColumnIndexOrThrow(columnName)
 return if (isNull(index)) null else getString(index)
 }X
 fun Cursor.getString(columnName: String): String = getStringOrNull(columnName)!! val firstName: String? = cursor.getStringOrNull("first_name")
  33. Extension Functions fun Cursor.getStringOrNull(columnName: String): String? {
 val index =

    getColumnIndexOrThrow(columnName)
 return if (isNull(index)) null else getString(index)
 }X
 fun Cursor.getString(columnName: String): String = getStringOrNull(columnName)!! val firstName: String? = cursor.getStringOrNull("first_name") if (firstName != null) { firstNameView.setText(firstName) }X
  34. Extension Functions fun Cursor.getStringOrNull(columnName: String): String? {
 val index =

    getColumnIndexOrThrow(columnName)
 return if (isNull(index)) null else getString(index)
 }X
 fun Cursor.getString(columnName: String): String = getStringOrNull(columnName)!! val firstName: String? = cursor.getStringOrNull("first_name") if (firstName != null) { firstNameView.setText(firstName) // firstName not String?, now String }X
  35. Extension Functions fun Cursor.getStringOrNull(columnName: String): String? {
 val index =

    getColumnIndexOrThrow(columnName)
 return if (isNull(index)) null else getString(index)
 }X
 fun Cursor.getString(columnName: String): String = getStringOrNull(columnName)!! val firstName: String? = cursor.getStringOrNull("first_name") firstNameView.setText(firstName ?: "Jake")
  36. Extension Functions fun Cursor.getStringOrNull(columnName: String): String? {
 val index =

    getColumnIndexOrThrow(columnName)
 return if (isNull(index)) null else getString(index)
 }X
 fun Cursor.getString(columnName: String): String = getStringOrNull(columnName)!! val firstName = cursor.getString("first_name")
  37. Extension Functions fun Cursor.getStringOrNull(columnName: String): String? {
 val index =

    getColumnIndexOrThrow(columnName)
 return if (isNull(index)) null else getString(index)
 }X
 fun Cursor.getString(columnName: String): String = getStringOrNull(columnName)!! val firstName: String = cursor.getString("first_name")
  38. Extension Functions fun Cursor.getStringOrNull(columnName: String): String? {
 val index =

    getColumnIndexOrThrow(columnName)
 return if (isNull(index)) null else getString(index)
 }X
 fun Cursor.getString(columnName: String): String = getStringOrNull(columnName)!! val firstName: String = cursor.getString("first_name") firstNameView.setText(firstName)
  39. Extension Functions fun Cursor.getStringOrNull(columnName: String): String? {
 val index =

    getColumnIndexOrThrow(columnName)
 return if (isNull(index)) null else getString(index)
 }X
 fun Cursor.getString(columnName: String): String = getStringOrNull(columnName)!! val firstName: String = cursor.getString("first_name") firstNameView.setText(firstName)
  40. Function Expressions { x, y -> x + y }

    { x: Int, y: Int -> x + y } { it.toString() } { x, y -> x + y } { x: Int, y: Int -> x + y }
  41. Function Expressions { x, y -> x + y }

    { x: Int, y: Int -> x + y } val sum = { x: Int, y: Int -> x + y } val sum: (Int, Int) -> Int = { x, y -> x + y } { it.toString() }
  42. Function Expressions { x, y -> x + y }

    { x: Int, y: Int -> x + y } val sum = { x: Int, y: Int -> x + y } val sum: (Int, Int) -> Int = { x, y -> x + y } { it.toString() }
  43. Function Expressions { x, y -> x + y }

    { x: Int, y: Int -> x + y } val sum = { x: Int, y: Int -> x + y } val sum: (Int, Int) -> Int = { x, y -> x + y } { it.toString() }
  44. Function Expressions { !it.isEmpty() } { it.length() > 4 }

    { it.matches("\\d{4}") } { luhnCheck(it) }
  45. Function Expressions val notEmpty: (String) -> Boolean = { !it.isEmpty()

    } val atLeastFour: (String) -> Boolean = { it.length() > 4 } val fourDigits: (String) -> Boolean = { it.matches("\\d{4}") } val validCreditCard: (String) -> Boolean = { luhnCheck(it) }
  46. Higher-Order Functions fun <T> List<T>.filter(predicate: (T) -> Boolean): List<T> {


    val newList = ArrayList<T>() // ...
 return newList
 }X
  47. Higher-Order Functions fun <T> List<T>.filter(predicate: (T) -> Boolean): List<T> {


    val newList = ArrayList<T>()
 for (item in this) { // ...
 }Y
 return newList
 }X
  48. Higher-Order Functions fun <T> List<T>.filter(predicate: (T) -> Boolean): List<T> {


    val newList = ArrayList<T>()
 for (item in this) {
 if (predicate(item)) { // ...
 }Z
 }Y
 return newList
 }X
  49. Higher-Order Functions fun <T> List<T>.filter(predicate: (T) -> Boolean): List<T> {


    val newList = ArrayList<T>()
 for (item in this) {
 if (predicate(item)) {
 newList.add(item)
 }Z
 }Y
 return newList
 }X
  50. Higher-Order Functions fun <T> List<T>.filter(predicate: (T) -> Boolean): List<T> {


    val newList = ArrayList<T>()
 for (item in this) {
 if (predicate(item)) {
 newList.add(item)
 }
 }
 return newList
 } val names = listOf("Jake", "Jesse", "Matt", "Alec")
 val jakes = names.filter { it == "Jake" }

  51. Higher-Order Functions data class Lock<T>(private val obj: T) {
 public

    fun acquire(func: (T) -> Unit) {
 synchronized (obj) {
 func(obj)
 }X
 }X
 }X
  52. Higher-Order Functions data class Lock<T>(private val obj: T) {
 public

    fun acquire(func: (T) -> Unit) {
 synchronized (obj) {
 func(obj)
 }X
 }X
 }X
  53. Higher-Order Functions data class Lock<T>(private val obj: T) {
 public

    fun acquire(func: (T) -> Unit) {
 synchronized (obj) {
 func(obj)
 }X
 }X
 }X
  54. Higher-Order Functions data class Lock<T>(private val obj: T) {
 public

    fun acquire(func: (T) -> Unit) {
 synchronized (obj) {
 func(obj)
 }X
 }X
 }X
  55. Higher-Order Functions data class Lock<T>(private val obj: T) {
 public

    fun acquire(func: (T) -> Unit) {
 synchronized (obj) {
 func(obj)
 }
 }
 }
  56. Higher-Order Functions data class Lock<T>(private val obj: T) {
 public

    fun acquire(func: (T) -> Unit) {
 synchronized (obj) {
 func(obj)
 }
 }
 } val readerLock = Lock(JsonReader(stream))
  57. Higher-Order Functions data class Lock<T>(private val obj: T) {
 public

    fun acquire(func: (T) -> Unit) {
 synchronized (obj) {
 func(obj)
 }
 }
 } val readerLock = Lock(JsonReader(stream))
 
 // Later
 readerLock.acquire { 
 println(it.readString())
 }
  58. Higher-Order Functions val notEmpty: (String) -> Boolean = { !it.isEmpty()

    } val atLeastFour: (String) -> Boolean = { it.length() > 4 } val fourDigits: (String) -> Boolean = { it.matches("\\d{4}") } val validCreditCard: (String) -> Boolean = { luhnCheck(it) }
  59. Higher-Order Functions val notEmpty: (String) -> Boolean = { !it.isEmpty()

    } val atLeastFour: (String) -> Boolean = { it.length() > 4 } val fourDigits: (String) -> Boolean = { it.matches("\\d{4}") } val validCreditCard: (String) -> Boolean = { luhnCheck(it) } firstName.validateWith(notEmpty) lastName.validateWith(notEmpty) username.validateWith(atLeastFour) pin.validateWith(fourDigits) creditCard.validateWith(validCreditCard) { !it.isEmpty() }
  60. Higher-Order Functions firstName.validateWith { !it.isEmpty() } lastName.validateWith { !it.isEmpty() }

    username.validateWith { it.length() > 4 } pin.validateWith { it.matches("\\d{4}") } creditCard.validateWith { luhnCheck(it) }
  61. Higher-Order Functions val notEmpty: (String) -> Boolean = { !it.isEmpty()

    } firstName.validateWith(notEmpty) lastName.validateWith(notEmpty) username.validateWith { it.length() > 4 } pin.validateWith { it.matches("\\d{4}") } creditCard.validateWith { luhnCheck(it) } { !it.isEmpty() }
  62. Extension Function Expressions • Extension Functions — Functions added to

    a type without modifying the original. • Function Expressions — Undeclared function bodies used an as expression (i.e., as data).
  63. Extension Function Expressions • Extension Functions — Functions added to

    a type without modifying the original. • Function Expressions — Undeclared function bodies used an as expression (i.e., as data). • Higher-Order Functions: A function which takes a function or returns a function.
  64. Extension Function Expressions db.beginTransaction();
 try {
 db.delete("users", "first_name = ?",

    new String[] { "Jake" });
 } finally {
 db.endTransaction();
 }X
  65. Extension Function Expressions db.beginTransaction();
 try {
 db.delete("users", "first_name = ?",

    new String[] { "Jake" });
 db.setTransactionSuccessful();
 } finally {
 db.endTransaction();
 }X
  66. Extension Function Expressions fun SQLiteDatabase.inTransaction(func: () -> Unit) {
 beginTransaction()


    try {
 func()
 setTransactionSuccessful()
 } finally {
 endTransaction()
 }
 }
  67. Extension Function Expressions fun SQLiteDatabase.inTransaction(func: () -> Unit) {
 beginTransaction()


    try {
 func(
 setTransactionSuccessful()
 } finally {
 endTransaction()
 }Y
 }X db.inTransaction { 
 }X )
  68. Extension Function Expressions fun SQLiteDatabase.inTransaction(func: () -> Unit) {
 beginTransaction()


    try {
 func(
 setTransactionSuccessful()
 } finally {
 endTransaction()
 }Y
 }X db.inTransaction { 
 db.delete("users", "first_name = ?", arrayOf("Jake"))
 }X )
  69. Extension Function Expressions fun SQLiteDatabase.inTransaction(func: () -> Unit) {
 beginTransaction()


    try {
 func(
 setTransactionSuccessful()
 } finally {
 endTransaction()
 }Y
 }X db.inTransaction { 
 db.delete("users", "first_name = ?", arrayOf("Jake"))
 }X )
  70. Extension Function Expressions fun SQLiteDatabase.inTransaction(func: (SQLiteDatabase) -> Unit) {
 beginTransaction()


    try {
 func(
 setTransactionSuccessful()
 } finally {
 endTransaction()
 }Y
 }X db.inTransaction { 
 db.delete("users", "first_name = ?", arrayOf("Jake"))
 }X )
  71. Extension Function Expressions fun SQLiteDatabase.inTransaction(func: (SQLiteDatabase) -> Unit) {
 beginTransaction()


    try {
 func(
 setTransactionSuccessful()
 } finally {
 endTransaction()
 }Y
 }X db.inTransaction { 
 db.delete("users", "first_name = ?", arrayOf("Jake"))
 }X )
  72. Extension Function Expressions fun SQLiteDatabase.inTransaction(func: (SQLiteDatabase) -> Unit) {
 beginTransaction()


    try {
 func(this
 setTransactionSuccessful()
 } finally {
 endTransaction()
 }Y
 }X db.inTransaction { 
 db.delete("users", "first_name = ?", arrayOf("Jake"))
 }X )
  73. Extension Function Expressions fun SQLiteDatabase.inTransaction(func: (SQLiteDatabase) -> Unit) {
 beginTransaction()


    try {
 func(this
 setTransactionSuccessful()
 } finally {
 endTransaction()
 }Y
 }X db.inTransaction { 
 db.delete("users", "first_name = ?", arrayOf("Jake"))
 }X )
  74. Extension Function Expressions fun SQLiteDatabase.inTransaction(func: (SQLiteDatabase) -> Unit) {
 beginTransaction()


    try {
 func(this
 setTransactionSuccessful()
 } finally {
 endTransaction()
 }Y
 }X db.inTransaction { 
 it.delete("users", "first_name = ?", arrayOf("Jake"))
 }X )
  75. Extension Function Expressions fun SQLiteDatabase.inTransaction(func: (SQLiteDatabase) -> Unit) {
 beginTransaction()


    try {
 func(this
 setTransactionSuccessful()
 } finally {
 endTransaction()
 }Y
 }X db.inTransaction { 
 it.delete("users", "first_name = ?", arrayOf("Jake"))
 }X )
  76. Extension Function Expressions fun SQLiteDatabase.inTransaction(func: (SQLiteDatabase) -> Unit) {
 beginTransaction()


    try {
 func(this
 setTransactionSuccessful()
 } finally {
 endTransaction()
 }Y
 }X db.inTransaction { 
 it.delete("users", "first_name = ?", arrayOf("Jake"))
 }X )
  77. Extension Function Expressions fun SQLiteDatabase.inTransaction(func: SQLiteDatabase.() -> Unit) {
 beginTransaction()


    try {
 func(this
 setTransactionSuccessful()
 } finally {
 endTransaction()
 }Y
 }X db.inTransaction { 
 it.delete("users", "first_name = ?", arrayOf("Jake"))
 }X )
  78. Extension Function Expressions fun SQLiteDatabase.inTransaction(func: SQLiteDatabase.() -> Unit) {
 beginTransaction()


    try {
 func(this
 setTransactionSuccessful()
 } finally {
 endTransaction()
 }Y
 }X db.inTransaction { 
 it.delete("users", "first_name = ?", arrayOf("Jake"))
 }X )
  79. Extension Function Expressions fun SQLiteDatabase.inTransaction(func: SQLiteDatabase.() -> Unit) {
 beginTransaction()


    try {
 this.func(
 setTransactionSuccessful()
 } finally {
 endTransaction()
 }Y
 }X db.inTransaction { 
 it.delete("users", "first_name = ?", arrayOf("Jake"))
 }X )
  80. Extension Function Expressions fun SQLiteDatabase.inTransaction(func: SQLiteDatabase.() -> Unit) {
 beginTransaction()


    try {
 func(
 setTransactionSuccessful()
 } finally {
 endTransaction()
 }Y
 }X db.inTransaction { 
 it.delete("users", "first_name = ?", arrayOf("Jake"))
 }X )
  81. Extension Function Expressions fun SQLiteDatabase.inTransaction(func: SQLiteDatabase.() -> Unit) {
 beginTransaction()


    try {
 func(
 setTransactionSuccessful()
 } finally {
 endTransaction()
 }Y
 }X db.inTransaction { 
 it.delete("users", "first_name = ?", arrayOf("Jake"))
 }X )
  82. Extension Function Expressions fun SQLiteDatabase.inTransaction(func: SQLiteDatabase.() -> Unit) {
 beginTransaction()


    try {
 func()
 setTransactionSuccessful()
 } finally {
 endTransaction()
 }Y
 }X db.inTransaction { 
 delete("users", "first_name = ?", arrayOf("Jake"))
 }X
  83. Extension Function Expressions fun SQLiteDatabase.inTransaction(func: SQLiteDatabase.() -> Unit) {
 beginTransaction()


    try {
 func()
 setTransactionSuccessful()
 } finally {
 endTransaction()
 }Y
 }X db.inTransaction { 
 delete("users", "first_name = ?", arrayOf("Jake"))
 }X
  84. Extension Function Expressions NEW MyClassKt$deleteUsers$1 DUP ALOAD 2 INVOKESPECIAL MyClassKt$deleteUsers$1.<init>

    (Ljava/lang/String;)V CHECKCAST kotlin/jvm/functions/Function1 INVOKESTATIC DbExtensionsKt.inTransaction (Landroid/database/sqlite/SQLiteDatabase;Lkotlin/jvm/functions/Function1;)V db.inTransaction { 
 delete("users", "first_name = ?", arrayOf("Jake"))
 }X
  85. Extension Function Expressions DbExtensions.inTransaction(db, new Function1<SQLiteDatabase, Unit>() {
 @Override public

    Unit invoke(SQLiteDatabase db) {
 db.delete("users", "first_name = ?", new String[] { "Jake "});
 return null;
 }
 }); db.inTransaction { 
 delete("users", "first_name = ?", arrayOf("Jake"))
 }X
  86. Extension Function Expressions fun SQLiteDatabase.inTransaction(func: SQLiteDatabase.() -> Unit) {
 beginTransaction()


    try {
 func()
 setTransactionSuccessful()
 } finally {
 endTransaction()
 }Y
 }X
  87. Extension Function Expressions inline fun SQLiteDatabase.inTransaction(func: SQLiteDatabase.() -> Unit) {


    beginTransaction()
 try {
 func()
 setTransactionSuccessful()
 } finally {
 endTransaction()
 }Y
 }X
  88. Extension Function Expressions L6 ALOAD 2 INVOKEVIRTUAL com/example/SQLiteDatabase.beginTransaction ()V L0

    NOP L9 ALOAD 2 CHECKCAST com/example/SQLiteDatabase ASTORE 3 L10 ALOAD 3 LDC "users" LDC "first_name = ?" ICONST_1 ANEWARRAY java/lang/String DUP ICONST_0 LDC "Jake" AASTORE CHECKCAST [Ljava/lang/String; INVOKEVIRTUAL com/example/SQLiteDatabase.delete (Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;)V L11 L12 GETSTATIC kotlin/Unit.INSTANCE : Lkotlin/Unit; POP L13 ALOAD 2 INVOKEVIRTUAL com/example/SQLiteDatabase.setTransactionSuccessful ()V L1 ALOAD 2 INVOKEVIRTUAL com/example/SQLiteDatabase.endTransaction ()V L14 GOTO L15 L2 ASTORE 3 L3 ALOAD 2 INVOKEVIRTUAL com/example/SQLiteDatabase.endTransaction ()V
  89. Extension Function Expressions db.beginTransaction();
 try {
 db.delete("users", "first_name = ?",

    new String[] { "Jake "});
 db.setTransactionSuccessful();
 } finally {
 db.endTransaction();
 }X
  90. Extension Function Expressions db.beginTransaction();
 try {
 db.delete("users", "first_name = ?",

    new String[] { "Jake "});
 db.setTransactionSuccessful();
 } finally {
 db.endTransaction();
 }X db.inTransaction { 
 delete("users", "first_name = ?", arrayOf("Jake"))
 }X + inline fun =
  91. Extension Function Expressions inline fun SharedPreferences.edit(func: SharedPreferences.Editor.() -> Unit) {


    val editor = edit()
 editor.func()
 editor.apply()
 }X preferences.edit { 
 putString("foo", "bar")
 putString("fizz", "buzz")
 remove("username")
 }X
  92. Extension Function Expressions inline fun SharedPreferences.edit(func: SharedPreferences.Editor.() -> Unit) {


    val editor = edit()
 editor.func()
 editor.apply()
 }X 
 fun SharedPreferences.Editor.set(pair: Pair<String, String>) =
 putString(pair.first, pair.second) preferences.edit { 
 putString("foo", "bar")
 putString("fizz", "buzz")
 remove("username")
 }X
  93. Extension Function Expressions inline fun SharedPreferences.edit(func: SharedPreferences.Editor.() -> Unit) {


    val editor = edit()
 editor.func()
 editor.apply()
 }X 
 fun SharedPreferences.Editor.set(pair: Pair<String, String>) =
 putString(pair.first, pair.second) preferences.edit {
 set("foo" to "bar")
 set("fizz" to "buzz")
 remove("username")
 }X 
 
 
 
 
 
 
 putString
 putString
  94. Extension Function Expressions inline fun notification(context: Context, func: Notification.Builder.() ->

    Unit): Notification {
 val builder = Notification.Builder(context)
 builder.func()
 return builder.build()
 }
  95. Extension Function Expressions inline fun notification(context: Context, func: Notification.Builder.() ->

    Unit): Notification {
 val builder = Notification.Builder(context)
 builder.func()
 return builder.build()
 } val n = notification(context) {
 setContentTitle("Hi")
 setSubText("Hello")
 }
  96. Extension Function Expressions verticalLayout {
 padding = dip(30)
 editText {


    hint = "Name"
 textSize = 24f
 }
 editText {
 hint = "Password"
 textSize = 24f
 }
 button("Login") {
 textSize = 26f
 }
 }