ANDROID 101 - BUILDING A SIMPLE APP WITH KOTLIN IN 90 MINUTES KAI KOENIG (@AGENTK)
HELLO HELLO I’m Kate! I’m an { Android Developer | GDG Organiser | Carpenter | 
 Backup Mum to all my neighbours cats | …} Find me on Twitter: @Mistyepd and I’m Kai! I’m a { Software Engineer | Pilot | GDG Organiser | 
 Gamer | Dad to 1 cat and 3 chickens | … } Find me on Twitter: @AgentK
HELLO CODE https://github.com/TheRealAgentK/ SummerOfTech-Android-2018
AGENDA ▸ What is Kotlin? ▸ Language idioms & concepts ▸ Kotlin and Android ▸ Anko DSL
MORE GDG WELLINTON
MORE WELLINGTON.KT
WHAT IS KOTLIN?
WHAT IS KOTLIN? SOME FUNDAMENTALS ▸ Statically typed programming language for the JVM and Android ▸ Started as internal language “Project Kotlin” at Jetbrains in 2010 ▸ Now: Open-Source, Apache License ▸ Kotlin SDK plus tool support for IntelliJ, Android Studio, Eclipse ▸ Named after an island in the Gulf of Finland
WHAT IS KOTLIN? MOTIVATION FOR KOTLIN ▸ The Java platform is awesome, but it has its issues: ▸ sometimes tied to backwards/legacy compatibility ▸ can be a very verbose language and produce bloated code ▸ type system has various flaws ▸ Kotlin aims to fix a lot of those issues ▸ compiles to Java 6 byte code therefore caters well for Android runtimes
LANGUAGE IDIOMS & CONCEPTS https://www.flickr.com/photos/geraldford/6976818221/
LANGUAGE IDIOMS & CONCEPTS OVERVIEW ▸ Immutability ▸ String templates & Enum classes ▸ Null safety ▸ Properties and Fields ▸ Type inference and casts ▸ Data classes ▸ Syntactic sugar (loops, ranges etc) ▸ Extension functions ▸ Lambdas ▸ Collection API ▸ Type-safe builders ▸ Java-Kotlin-Interop
LANGUAGE IDIOMS & CONCEPTS IMMUTABILITY ▸ Built-in support for mutable and immutable variables, properties and fields ▸ Keywords var and val ▸ val - immutable (recommended) ▸ var - mutable ▸ Similar concept applies for class properties, val creates getters, var creates getters and setters (more later) val a: Int = 1 val b = 1 val c: Int c = 1 var x = 23 x += 1
LANGUAGE IDIOMS & CONCEPTS STRING TEMPLATES & ENUM CLASSES (I) ▸ Kotlin Strings can contain template expressions ▸ String templates start with a $ character and ▸ can contain simple references such as $s, as well as ▸ complex expressions in curly braces: 
 ${s.length} val s = "abc" val str = "$s.length is ${s.length}" Output: abc.length is 3
LANGUAGE IDIOMS & CONCEPTS STRING TEMPLATES & ENUM CLASSES (II) ▸ Kotlin has a dedicated and expressive enum class ▸ Can be used very nicely in conjunction with String templates enum class Locale(val hello: String) { DE_DE("Hallo"), EN_NZ("Hello"), MI_NZ("Kia Ora") } class Customer(val firstName:String, val lastName:String, val locale: Locale = Locale.DE_DE) { fun sayHello() = println( "${locale.hello}, $firstName $lastName") } fun main(args : Array<String>) { val myCustomer = Customer("Sandra", "Musterfrau", Locale.MI_NZ) myCustomer.sayHello() }
LANGUAGE IDIOMS & CONCEPTS NULL SAFETY ▸ Motivation: A better way to deal with NPEs ▸ Kotlin differentiates nullable types from non- nullable types by adding a ? to the type: ▸ String: no nullable ▸ String?: nullable ▸ Handle manually ▸ Use Safe Call operator ?. ▸ Use the !! operator to allow/trigger a NPE // Won't compile var lastName: String = null // Will compile var lastNameNullable: String? = null // Will also not compile println(lastNameNullable.length) // Option 1 (-1) println(if (lastNameNullable != null) lastNameNullable.length else -1) // Option 2 (null) println(lastNameNullable?.length) // Option 3 (NPE) println(lastNameNullable!!.length)
LANGUAGE IDIOMS & CONCEPTS PROPERTIES AND FIELDS ▸ Kotlin classes have mutable or immutable properties ▸ Default getter/setters for properties, can be customised ▸ An automated backing field can be provided by the compiler (if required) ▸ Alternative: use an explicit backing property var counter = 0 set(value) { if (value >= 0) field = value } public class Address { public var name: String = ... public var street: String = ... public var city: String = ... public var state: String? = ... public var zip: String = ... }
LANGUAGE IDIOMS & CONCEPTS TYPE INFERENCE AND CASTS (I) ▸ When possible, Kotlin will infer the type of variables ▸ Explicit conversions, type widening and inference ▸ Smaller types are not subtypes of bigger types, no implicit conversion ▸ Types are often inferred from the context val b: Byte = 1 // This won't work val i: Int = b // This will val i: Int = b.toInt() val l: Long = 1L + 3
LANGUAGE IDIOMS & CONCEPTS TYPE INFERENCE AND CASTS (II) ▸ is or !is checks if an object adheres to a certain type ▸ Smart cast: Compiler tracks is-expressions for immutable values ▸ works for val local variables and private, internal or in-module performed casts ▸ works for var local variables if the variable hasn’t been modified between check and usage, never for var properties fun whatIs(x: Any) { when (x) { is Int -> println(x + 42) is String -> println(x.length) is IntArray -> println(x.sum()) } } whatIs(4) // 46 whatIs("4") // 1 whatIs(intArrayOf(1,2,3,4,5)) // 15
LANGUAGE IDIOMS & CONCEPTS DATA CLASSES ▸ The POJOs/Beans of other languages ▸ Data classes implicitly create: ▸ getters/setters (non-data classes have those too) - recommend to use val as often as possible. ▸ useful implementations for equals(), hashCode(), toString(), copy() ▸ copy() has default parameters and can be used to alter a copy data class ChromeEncryptedPayload( val encryptedPayload: String, val encryptionHeader: String, val cryptoKeyHeader: String) val pl = ChromeEncryptedPayload( encryptedPayload = "...", encryptionHeader = "...", cryptoKeyHeader = "...") val anotherPl = pl.copy( encryptedPayload = "...")
LANGUAGE IDIOMS & CONCEPTS EXTENSION FUNCTIONS ▸ Allow adding new functionality to a class without inheritance or Decorators ▸ Kotlin has extension functions as well as extension properties ▸ Resolved statically, don’t actually modify the class (excellent example why this has to be the case at http:// goo.gl/EN6bTs fun Int.sum(otherInt: Int): Int = this + otherInt 3.sum(7) fun Activity.toast(message: CharSequence, duration: Int = TOAST.LENGTH_SHORT) { Toast.makeText(this, message, duration).show() } // In onCreate of an Activity override fun onCreate(...) { ... toast("Hi there") ... }
LANGUAGE IDIOMS & CONCEPTS LAMBDAS ▸ Anonymous function or “function literal”, closely related to the ideas of Higher-Order-Functions val sum = { x: Int, y: Int -> x + y } val sum: (Int, Int) -> Int = { x, y -> x + y } private fun convertPetListToDomain(list: List<Pet>): List<PetDomain> { return list.map { convertPetItemToDomain(it) } } private fun convertPetItemToDomain(pet: Pet): PetDomain { return PetDomain(pet.age,pet.size,pet.id,pet.name,pet.sex,pet.breed) }
LANGUAGE IDIOMS & CONCEPTS TYPE-SAFE BUILDERS (I) ▸ Builders are a very popular approach in Groovy to define data in a declarative way ▸ Often used for: ▸ generating XML or JSON ▸ UI layout (Swing components) etc ▸ In Kotlin, builders even can be type- checked JsonBuilder builder = new JsonBuilder() builder.records { car { name 'HSV Maloo' make 'Holden' year 2006 country 'Australia' } } String json = JsonOutput.prettyPrint (builder.toString())
LANGUAGE IDIOMS & CONCEPTS TYPE-SAFE BUILDERS (II) ▸ html() is a function with a lambda as an argument (init) ▸ init’s type is a function type with receiver, this allows you to: ▸ pass receiver (of type HTML) to function ▸ call members of instance inside the function fun result(args: Array<String>) = html { head { title {”HTML in Kotlin"} } body { ... } } fun html(init: HTML.() -> Unit): HTML { val html = HTML() html.init() return html }
LANGUAGE IDIOMS & CONCEPTS TYPE-SAFE BUILDERS (III) ▸ HTML class has functions to build the head and the body elements of the DSL. ▸ Not shown: classes further down in the hierarchy: ▸ Head, Body etc. ▸ Complete HTML builder example at: http://goo.gl/TndcC9 class HTML { ... fun head(headBuilder: Head.() -> Unit) { head = Head() head?.headBuilder() } fun body(bodyBuilder: Body.() -> Unit) { body = Body() body?.bodyBuilder() } }
LANGUAGE IDIOMS & CONCEPTS JAVA-KOTLIN-INTEROP ▸ Java and Kotlin are fully interoperable from an integration point of view ▸ Your Java code can call and use Kotlin code ▸ Your Kotlin code can call and use Java code ▸ The latter is in particular useful because it means you can continue to use pretty much any existing Android/Java library ▸ Check out Hendrik Kokocinski’s sample Kotlin app that uses all kinds of well known Android/Java libs: https://goo.gl/xdYqf5
LANGUAGE IDIOMS & CONCEPTS OVERVIEW ▸ Immutability ▸ String templates & Enum classes ▸ Null safety ▸ Properties and Fields ▸ Type inference and casts ▸ Data classes ▸ Syntactic sugar (loops, ranges etc) ▸ Extension functions ▸ Lambdas ▸ Collection API ▸ Type-safe builders ▸ Java-Kotlin-Interop
KOTLIN AND ANDROID https://realm.io/assets/img/news/tutorial-kotlin-anko-cover.png
APP STEP 1 - KOTLIN SETUP ▸ Setup Kotlin Plugin and tooling ▸ Automated vs. manual
APP STEP 2 - REFACTOR JAVA -> KOTLIN ▸ Kotlin Source Path
APP STEP 3 - KOTLIN ANDROID EXTENSIONS ▸ Finding views with KAE (built into the plugin)
APP STEP 4 - MORE KAE ▸ KAE Click handler - compare to classic Kotlin code ▸ Lambdas
APP STEP 5 - BUTTERKNIFE ▸ View Bindings with Butterknife in Kotlin ▸ KAPT setup
APP STEP 6 - RECYCLERVIEW AND SOME DATA ▸ Adding Adapter and RecyclerView ▸ Displaying hardcoded data for now
APP STEP 7 - DATA (I) ▸ Loading and returning some hard JSON sample data ▸ Companion object ▸ No UI changes, use debugger in MainActivity
APP STEP 8 - DATA (II) / GSON PARSING ▸ Kotlin data classes ▸ GSON parsing ▸ String templates ▸ No UI changes, use debugger in MainActivity
APP STEP 9 - ARCHITECTURE ▸ Command pattern ▸ Introducing Anko for async ▸ More String templates ▸ with ▸ Interface ▸ .map
ANKO DSL
ANKO DSL WHAT IS A DSL? ▸ Domain-Specific Language ▸ Limited expressiveness: ▸ DSLs are usually not general-purpose languages ▸ strongly focussed on a particular domain ▸ examples: SQL, Ant XML, XSLT, Gradle etc.
ANKO DSL A DSL FOR LAYOUTS ▸ The most important element of Anko is the Layout DSL ▸ Idea: replace XML layout definitions by Kotlin code - without having to build the layout in a fully programmatic sense ▸ Modular: as we’re talking about UI/Layout, it’s very important to select the right library for your minSDKVersion ▸ Extensible: you can add your own DSL elements for custom UI controls
ANKO DSL LAYOUT XML <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <EditText android:layout_width="match_parent" android:gravity="center" android:text="@string/empty_todos_message" android:layout_weight="7" android:layout_height="wrap_content" /> <Button android:layout_width="match_parent" android:layout_weight="1" android:text="Say Hello" android:layout_height="0dp" /> </LinearLayout>
ANKO DSL PROGRAMMATIC LAYOUT IN KOTLIN val act = this val layout = LinearLayout(act) layout.orientation = LinearLayout.VERTICAL val name = EditText(act) val button = Button(act) button.text = "Say Hello" button.setOnClickListener { Toast.makeText(act, "Hello, ${name.text}!", Toast.LENGTH_SHORT).show() } layout.addView(name) layout.addView(button)
ANKO DSL ANKO DSL verticalLayout { val name = editText() button("Say Hello") { onClick { toast("Hello, ${name.text}!") } } }
ANKO DSL ANKO DSL INTERNALS ▸ Anko DSL example from previous slide looks very similar to the earlier HTML builder example ▸ Anko uses extension functions arranged into type-safe builders and lambdas ▸ You don’t have to write all those extensions by hand though - Anko generates them based on the Android SDK’s android.jar
ANKO DSL GETTING STARTED WITH ANKO DSL (I) ▸ Depending on minSdkVersion of project, import:
 compile "org.jetbrains.anko:anko-sdk{15|19|21|23}:0.9" ▸ If the project uses an Android Support library, import matching Anko library:
 compile "org.jetbrains.anko:anko-recyclerview-v7:0.9"
ANKO DSL GETTING STARTED WITH ANKO DSL (II) ▸ General approach: ▸ Anko DSL automatically becomes available in onCreate() in an Activity ▸ no need for setContentView(), Anko DSL also automatically sets the content view for activities override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) verticalLayout { padding = dip(30) editText { hint = "Name" textSize = 24f } editText { hint = "Password" textSize = 24f } button("Login") { textSize = 26f } } }
ANKO DSL ANKO DSL IN FRAGMENTS ▸ In fragments, use 
 onCreateView(…) ▸ Returns UI {…}.view: ▸ mandatory before Anko 0.8 ▸ works well for Fragments ▸ createTodo() is a fragment-private method override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? { return UI { verticalLayout { padding = dip(24) var title = editText { id = R.id.title hintResource = R.string.hint } ... button { id = R.id.add textResource = R.string.add onClick { view -> createTodo(title, desc) } } } }.view }
ANKO DSL ANKO COMPONENTS (I) ▸ Often it’s nicer to have UI code separated from onCreate or other livecycle methods ▸ AnkoComponent helps organising your UI code in their own classes
ANKO DSL ANKO COMPONENTS (II) override fun onCreateView(...)= EditFragmentUI().createView(AnkoContext.create(ctx,this)) class EditFragmentUI : AnkoComponent<EditFragment> { override fun createView(ui: AnkoContext<EditFragment>) = with(ui) { verticalLayout { padding = dip(24) var title = editText { id = R.id.title hintResource = R.string.hint } ... button { id = R.id.add textResource = R.string.add onClick { view -> ui.owner.createTodoFrom(title, desc) } } } } }
ANKO DSL ANKO COMPONENTS (III) ▸ Anko Preview plugin for AnkoComponent layouts ▸ Get it here: http://goo.gl/5CVmAA ▸ Can preview layouts and convert XML to Anko DSL ▸ Can be fiddly to get going with AS, Kotlin plugin versions
ANKO DSL EXTENDING ANKOS DSL FUNCTIONALITY (I) ▸ Multiple ways to do this: ▸ insert an existing XML layout into an Anko DSL declaration:
 ▸ adding new DSL elements to the language include<View>(R.layout.mylayout) { ... } inline fun ViewManager.customView(theme: Int = 0) = customView(theme) {} inline fun ViewManager.customView(theme: Int = 0, init: CustomView.() -> Unit) = ankoView({ CustomView(it) }, theme, init) inline fun Activity.customView(theme: Int = 0) = customView(theme) {} inline fun Activity.customView(theme: Int = 0, init: CustomView.() -> Unit) = ankoView({ CustomView(it) }, theme, init)
ANKO DSL EXTENDING ANKOS DSL FUNCTIONALITY (II) ▸ Extending Anko’s DSL to support your own custom view groups is currently rather painful ▸ Essentially it comes down to .lparams (for layout purposes) not being easily accessible ▸ More here: ▸ http://goo.gl/qpb3SL ▸ http://goo.gl/tMHs2c ▸ Fix targeted for Anko 0.9.1
THE HIDDEN PARTS OF ANKO
THE HIDDEN PARTS OF ANKO BUT THERE’S MORE ▸ Intent wrappers for various purposes: e.g. sendSMS(number, [text]) ▸ Intent builders ▸ Service shortcuts ▸ Configuration qualifiers: configuration(screenSize = ScreenSize.LARGE, orientation = Orientation.LANDSCAPE) { … } ▸ Asynchronous tasks ▸ SQLLite
THE HIDDEN PARTS OF ANKO INTENT WRAPPERS AND SERVICE SHORTCUTS ▸ Anko provides wrappers for commonly used Intents: ▸ makeCall(number), sendSMS(number, text), browse(url) etc. ▸ Shortcuts to Android services: ▸ notificationManager, displayManager, sensorManager etc. ▸ Useful, but both not major features of Anko
THE HIDDEN PARTS OF ANKO INTENT BUILDERS ▸ Syntactic sugar to cut down the amount of code needed to start a new activity val intent = Intent(this, javaClass<MyActivity>()) intent.putExtra("customerId", 4711) intent.putExtra("country", "NZ") startActivity(intent) startActivity(Intent(this, MyActivity::class.java). putExtra("customerId", 4711).putExtra("country", "NZ")) startActivity<MyActivity>("customerId" to 4711, "country" to "NZ")
THE HIDDEN PARTS OF ANKO CONFIGURATION QUALIFIERS ▸ “CSS Media Queries for Android” ▸ Screen features: ▸ screenSize, density, orientation, long, 
 nightMode, rightToLeft, smallestWidth ▸ SDK versions: ▸ fromSdk, sdk ▸ Other: ▸ language, uiMode configuration(screenSize = ScreenSize.LARGE, orientation = Orientation.LANDSCAPE) { /* This code will be only executed if the screen is large and its orientation is landscape */ }
THE HIDDEN PARTS OF ANKO ASYNC DSL ▸ Does anyone enjoy working with AsyncTasks? ▸ Anko: async and asyncResult (return future respectively future with result) async() { val result = PetFindCommand("90210","cat").execute() uiThread { animalList.adapter = AnimalListAdapter(result, object: AnimalListAdapter.ItemClickListener{ override fun invoke(pet:Pet) { toast(pet.name) } } ) } }
THE HIDDEN PARTS OF ANKO SQLITE (I) ▸ Working with SQLite usually requires a lot of boilerplate code and try/catch- structures, issues around concurrency, dealing with cached code and references etc. ▸ Anko aims to make that easier ▸ Dependency: compile ‘org.jetbrains.anko:anko-sqlite:0.9' ▸ Setup class extending ManagedSQLiteOpenHelper in your code
THE HIDDEN PARTS OF ANKO SQLITE (II) ▸ database.use ensures DB is opened and closed correctly ▸ Asynchronous use of the DB is possible through Anko’s async DSL ▸ Important: There can still be SQLiteExceptions when handling SQL code - Anko doesn’t abstract those. ▸ Handling of cursors and parsing data via lambdas database.use { createTable("Customer", ifNotExists = true, "id" to INTEGER + PRIMARY_KEY + UNIQUE, "name" to TEXT, "photo" to BLOB) }
APP STEP 10 - CLICK ON LIST ▸ Adapter/RecyclerView click handler changes ▸ when-statement
APP STEP 11 - EXCEPTIONS ▸ Exception handler in Anko
APP STEP 12 - ANKO DSL ▸ Anko layout for main view ▸ Removing layout XML and replacing it with Anko DSL
APP STEP 13 - ANKO COMPONENTS ▸ Refactoring into Anko component
APP STEP 14 ▸ Mini refactoring for better testing ▸ jUnit tests in Kotlin
APP STEP 15 ▸ Using Spek for BDD testing
APP IDEAS ▸ Add second Activity or Fragment to display and edit details ▸ Change layout to ConstraintLayout ▸ Use Kotson instead of Gson ▸ Store data locally ▸ Change RecyclerView to Anko Layout DSL ▸ Use Butterknife instead of Kotterknife ▸ Write some proper tests ▸ Try Android integration tests
MORE GDG WELLINTON
MORE WELLINGTON.KT
RESOURCES RESOURCES ▸ Kotlin: http://kotlinlang.org ▸ Anko: https://github.com/Kotlin/anko ▸ Kotter Knife: https://github.com/JakeWharton/kotterknife ▸ Spek: http://jetbrains.github.io/spek/ ▸ Kotson: https://github.com/SalomonBrys/Kotson
RESOURCES GET IN TOUCH Kai Koenig Email: kai@ventego-creative.co.nz Twitter: @AgentK Kate Henderson Email: hi@kate.nz Twitter: @Mistyepd

Android 101 - Building a simple app with Kotlin in 90 minutes

  • 1.
    ANDROID 101 -BUILDING A SIMPLE APP WITH KOTLIN IN 90 MINUTES KAI KOENIG (@AGENTK)
  • 2.
    HELLO HELLO I’m Kate! I’m an{ Android Developer | GDG Organiser | Carpenter | 
 Backup Mum to all my neighbours cats | …} Find me on Twitter: @Mistyepd and I’m Kai! I’m a { Software Engineer | Pilot | GDG Organiser | 
 Gamer | Dad to 1 cat and 3 chickens | … } Find me on Twitter: @AgentK
  • 3.
  • 4.
    AGENDA ▸ What isKotlin? ▸ Language idioms & concepts ▸ Kotlin and Android ▸ Anko DSL
  • 5.
  • 6.
  • 7.
  • 8.
    WHAT IS KOTLIN? SOMEFUNDAMENTALS ▸ Statically typed programming language for the JVM and Android ▸ Started as internal language “Project Kotlin” at Jetbrains in 2010 ▸ Now: Open-Source, Apache License ▸ Kotlin SDK plus tool support for IntelliJ, Android Studio, Eclipse ▸ Named after an island in the Gulf of Finland
  • 9.
    WHAT IS KOTLIN? MOTIVATIONFOR KOTLIN ▸ The Java platform is awesome, but it has its issues: ▸ sometimes tied to backwards/legacy compatibility ▸ can be a very verbose language and produce bloated code ▸ type system has various flaws ▸ Kotlin aims to fix a lot of those issues ▸ compiles to Java 6 byte code therefore caters well for Android runtimes
  • 10.
  • 11.
    LANGUAGE IDIOMS &CONCEPTS OVERVIEW ▸ Immutability ▸ String templates & Enum classes ▸ Null safety ▸ Properties and Fields ▸ Type inference and casts ▸ Data classes ▸ Syntactic sugar (loops, ranges etc) ▸ Extension functions ▸ Lambdas ▸ Collection API ▸ Type-safe builders ▸ Java-Kotlin-Interop
  • 12.
    LANGUAGE IDIOMS &CONCEPTS IMMUTABILITY ▸ Built-in support for mutable and immutable variables, properties and fields ▸ Keywords var and val ▸ val - immutable (recommended) ▸ var - mutable ▸ Similar concept applies for class properties, val creates getters, var creates getters and setters (more later) val a: Int = 1 val b = 1 val c: Int c = 1 var x = 23 x += 1
  • 13.
    LANGUAGE IDIOMS &CONCEPTS STRING TEMPLATES & ENUM CLASSES (I) ▸ Kotlin Strings can contain template expressions ▸ String templates start with a $ character and ▸ can contain simple references such as $s, as well as ▸ complex expressions in curly braces: 
 ${s.length} val s = "abc" val str = "$s.length is ${s.length}" Output: abc.length is 3
  • 14.
    LANGUAGE IDIOMS &CONCEPTS STRING TEMPLATES & ENUM CLASSES (II) ▸ Kotlin has a dedicated and expressive enum class ▸ Can be used very nicely in conjunction with String templates enum class Locale(val hello: String) { DE_DE("Hallo"), EN_NZ("Hello"), MI_NZ("Kia Ora") } class Customer(val firstName:String, val lastName:String, val locale: Locale = Locale.DE_DE) { fun sayHello() = println( "${locale.hello}, $firstName $lastName") } fun main(args : Array<String>) { val myCustomer = Customer("Sandra", "Musterfrau", Locale.MI_NZ) myCustomer.sayHello() }
  • 15.
    LANGUAGE IDIOMS &CONCEPTS NULL SAFETY ▸ Motivation: A better way to deal with NPEs ▸ Kotlin differentiates nullable types from non- nullable types by adding a ? to the type: ▸ String: no nullable ▸ String?: nullable ▸ Handle manually ▸ Use Safe Call operator ?. ▸ Use the !! operator to allow/trigger a NPE // Won't compile var lastName: String = null // Will compile var lastNameNullable: String? = null // Will also not compile println(lastNameNullable.length) // Option 1 (-1) println(if (lastNameNullable != null) lastNameNullable.length else -1) // Option 2 (null) println(lastNameNullable?.length) // Option 3 (NPE) println(lastNameNullable!!.length)
  • 16.
    LANGUAGE IDIOMS &CONCEPTS PROPERTIES AND FIELDS ▸ Kotlin classes have mutable or immutable properties ▸ Default getter/setters for properties, can be customised ▸ An automated backing field can be provided by the compiler (if required) ▸ Alternative: use an explicit backing property var counter = 0 set(value) { if (value >= 0) field = value } public class Address { public var name: String = ... public var street: String = ... public var city: String = ... public var state: String? = ... public var zip: String = ... }
  • 17.
    LANGUAGE IDIOMS &CONCEPTS TYPE INFERENCE AND CASTS (I) ▸ When possible, Kotlin will infer the type of variables ▸ Explicit conversions, type widening and inference ▸ Smaller types are not subtypes of bigger types, no implicit conversion ▸ Types are often inferred from the context val b: Byte = 1 // This won't work val i: Int = b // This will val i: Int = b.toInt() val l: Long = 1L + 3
  • 18.
    LANGUAGE IDIOMS &CONCEPTS TYPE INFERENCE AND CASTS (II) ▸ is or !is checks if an object adheres to a certain type ▸ Smart cast: Compiler tracks is-expressions for immutable values ▸ works for val local variables and private, internal or in-module performed casts ▸ works for var local variables if the variable hasn’t been modified between check and usage, never for var properties fun whatIs(x: Any) { when (x) { is Int -> println(x + 42) is String -> println(x.length) is IntArray -> println(x.sum()) } } whatIs(4) // 46 whatIs("4") // 1 whatIs(intArrayOf(1,2,3,4,5)) // 15
  • 19.
    LANGUAGE IDIOMS &CONCEPTS DATA CLASSES ▸ The POJOs/Beans of other languages ▸ Data classes implicitly create: ▸ getters/setters (non-data classes have those too) - recommend to use val as often as possible. ▸ useful implementations for equals(), hashCode(), toString(), copy() ▸ copy() has default parameters and can be used to alter a copy data class ChromeEncryptedPayload( val encryptedPayload: String, val encryptionHeader: String, val cryptoKeyHeader: String) val pl = ChromeEncryptedPayload( encryptedPayload = "...", encryptionHeader = "...", cryptoKeyHeader = "...") val anotherPl = pl.copy( encryptedPayload = "...")
  • 20.
    LANGUAGE IDIOMS &CONCEPTS EXTENSION FUNCTIONS ▸ Allow adding new functionality to a class without inheritance or Decorators ▸ Kotlin has extension functions as well as extension properties ▸ Resolved statically, don’t actually modify the class (excellent example why this has to be the case at http:// goo.gl/EN6bTs fun Int.sum(otherInt: Int): Int = this + otherInt 3.sum(7) fun Activity.toast(message: CharSequence, duration: Int = TOAST.LENGTH_SHORT) { Toast.makeText(this, message, duration).show() } // In onCreate of an Activity override fun onCreate(...) { ... toast("Hi there") ... }
  • 21.
    LANGUAGE IDIOMS &CONCEPTS LAMBDAS ▸ Anonymous function or “function literal”, closely related to the ideas of Higher-Order-Functions val sum = { x: Int, y: Int -> x + y } val sum: (Int, Int) -> Int = { x, y -> x + y } private fun convertPetListToDomain(list: List<Pet>): List<PetDomain> { return list.map { convertPetItemToDomain(it) } } private fun convertPetItemToDomain(pet: Pet): PetDomain { return PetDomain(pet.age,pet.size,pet.id,pet.name,pet.sex,pet.breed) }
  • 22.
    LANGUAGE IDIOMS &CONCEPTS TYPE-SAFE BUILDERS (I) ▸ Builders are a very popular approach in Groovy to define data in a declarative way ▸ Often used for: ▸ generating XML or JSON ▸ UI layout (Swing components) etc ▸ In Kotlin, builders even can be type- checked JsonBuilder builder = new JsonBuilder() builder.records { car { name 'HSV Maloo' make 'Holden' year 2006 country 'Australia' } } String json = JsonOutput.prettyPrint (builder.toString())
  • 23.
    LANGUAGE IDIOMS &CONCEPTS TYPE-SAFE BUILDERS (II) ▸ html() is a function with a lambda as an argument (init) ▸ init’s type is a function type with receiver, this allows you to: ▸ pass receiver (of type HTML) to function ▸ call members of instance inside the function fun result(args: Array<String>) = html { head { title {”HTML in Kotlin"} } body { ... } } fun html(init: HTML.() -> Unit): HTML { val html = HTML() html.init() return html }
  • 24.
    LANGUAGE IDIOMS &CONCEPTS TYPE-SAFE BUILDERS (III) ▸ HTML class has functions to build the head and the body elements of the DSL. ▸ Not shown: classes further down in the hierarchy: ▸ Head, Body etc. ▸ Complete HTML builder example at: http://goo.gl/TndcC9 class HTML { ... fun head(headBuilder: Head.() -> Unit) { head = Head() head?.headBuilder() } fun body(bodyBuilder: Body.() -> Unit) { body = Body() body?.bodyBuilder() } }
  • 25.
    LANGUAGE IDIOMS &CONCEPTS JAVA-KOTLIN-INTEROP ▸ Java and Kotlin are fully interoperable from an integration point of view ▸ Your Java code can call and use Kotlin code ▸ Your Kotlin code can call and use Java code ▸ The latter is in particular useful because it means you can continue to use pretty much any existing Android/Java library ▸ Check out Hendrik Kokocinski’s sample Kotlin app that uses all kinds of well known Android/Java libs: https://goo.gl/xdYqf5
  • 26.
    LANGUAGE IDIOMS &CONCEPTS OVERVIEW ▸ Immutability ▸ String templates & Enum classes ▸ Null safety ▸ Properties and Fields ▸ Type inference and casts ▸ Data classes ▸ Syntactic sugar (loops, ranges etc) ▸ Extension functions ▸ Lambdas ▸ Collection API ▸ Type-safe builders ▸ Java-Kotlin-Interop
  • 27.
  • 28.
    APP STEP 1 -KOTLIN SETUP ▸ Setup Kotlin Plugin and tooling ▸ Automated vs. manual
  • 29.
    APP STEP 2 -REFACTOR JAVA -> KOTLIN ▸ Kotlin Source Path
  • 30.
    APP STEP 3 -KOTLIN ANDROID EXTENSIONS ▸ Finding views with KAE (built into the plugin)
  • 31.
    APP STEP 4 -MORE KAE ▸ KAE Click handler - compare to classic Kotlin code ▸ Lambdas
  • 32.
    APP STEP 5 -BUTTERKNIFE ▸ View Bindings with Butterknife in Kotlin ▸ KAPT setup
  • 33.
    APP STEP 6 -RECYCLERVIEW AND SOME DATA ▸ Adding Adapter and RecyclerView ▸ Displaying hardcoded data for now
  • 34.
    APP STEP 7 -DATA (I) ▸ Loading and returning some hard JSON sample data ▸ Companion object ▸ No UI changes, use debugger in MainActivity
  • 35.
    APP STEP 8 -DATA (II) / GSON PARSING ▸ Kotlin data classes ▸ GSON parsing ▸ String templates ▸ No UI changes, use debugger in MainActivity
  • 36.
    APP STEP 9 -ARCHITECTURE ▸ Command pattern ▸ Introducing Anko for async ▸ More String templates ▸ with ▸ Interface ▸ .map
  • 37.
  • 38.
    ANKO DSL WHAT ISA DSL? ▸ Domain-Specific Language ▸ Limited expressiveness: ▸ DSLs are usually not general-purpose languages ▸ strongly focussed on a particular domain ▸ examples: SQL, Ant XML, XSLT, Gradle etc.
  • 39.
    ANKO DSL A DSLFOR LAYOUTS ▸ The most important element of Anko is the Layout DSL ▸ Idea: replace XML layout definitions by Kotlin code - without having to build the layout in a fully programmatic sense ▸ Modular: as we’re talking about UI/Layout, it’s very important to select the right library for your minSDKVersion ▸ Extensible: you can add your own DSL elements for custom UI controls
  • 40.
    ANKO DSL LAYOUT XML <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <EditText android:layout_width="match_parent" android:gravity="center" android:text="@string/empty_todos_message" android:layout_weight="7" android:layout_height="wrap_content" /> <Button android:layout_width="match_parent" android:layout_weight="1" android:text="Say Hello" android:layout_height="0dp" /> </LinearLayout>
  • 41.
    ANKO DSL PROGRAMMATIC LAYOUTIN KOTLIN val act = this val layout = LinearLayout(act) layout.orientation = LinearLayout.VERTICAL val name = EditText(act) val button = Button(act) button.text = "Say Hello" button.setOnClickListener { Toast.makeText(act, "Hello, ${name.text}!", Toast.LENGTH_SHORT).show() } layout.addView(name) layout.addView(button)
  • 42.
    ANKO DSL ANKO DSL verticalLayout{ val name = editText() button("Say Hello") { onClick { toast("Hello, ${name.text}!") } } }
  • 43.
    ANKO DSL ANKO DSLINTERNALS ▸ Anko DSL example from previous slide looks very similar to the earlier HTML builder example ▸ Anko uses extension functions arranged into type-safe builders and lambdas ▸ You don’t have to write all those extensions by hand though - Anko generates them based on the Android SDK’s android.jar
  • 44.
    ANKO DSL GETTING STARTEDWITH ANKO DSL (I) ▸ Depending on minSdkVersion of project, import:
 compile "org.jetbrains.anko:anko-sdk{15|19|21|23}:0.9" ▸ If the project uses an Android Support library, import matching Anko library:
 compile "org.jetbrains.anko:anko-recyclerview-v7:0.9"
  • 45.
    ANKO DSL GETTING STARTEDWITH ANKO DSL (II) ▸ General approach: ▸ Anko DSL automatically becomes available in onCreate() in an Activity ▸ no need for setContentView(), Anko DSL also automatically sets the content view for activities override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) verticalLayout { padding = dip(30) editText { hint = "Name" textSize = 24f } editText { hint = "Password" textSize = 24f } button("Login") { textSize = 26f } } }
  • 46.
    ANKO DSL ANKO DSLIN FRAGMENTS ▸ In fragments, use 
 onCreateView(…) ▸ Returns UI {…}.view: ▸ mandatory before Anko 0.8 ▸ works well for Fragments ▸ createTodo() is a fragment-private method override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? { return UI { verticalLayout { padding = dip(24) var title = editText { id = R.id.title hintResource = R.string.hint } ... button { id = R.id.add textResource = R.string.add onClick { view -> createTodo(title, desc) } } } }.view }
  • 47.
    ANKO DSL ANKO COMPONENTS(I) ▸ Often it’s nicer to have UI code separated from onCreate or other livecycle methods ▸ AnkoComponent helps organising your UI code in their own classes
  • 48.
    ANKO DSL ANKO COMPONENTS(II) override fun onCreateView(...)= EditFragmentUI().createView(AnkoContext.create(ctx,this)) class EditFragmentUI : AnkoComponent<EditFragment> { override fun createView(ui: AnkoContext<EditFragment>) = with(ui) { verticalLayout { padding = dip(24) var title = editText { id = R.id.title hintResource = R.string.hint } ... button { id = R.id.add textResource = R.string.add onClick { view -> ui.owner.createTodoFrom(title, desc) } } } } }
  • 49.
    ANKO DSL ANKO COMPONENTS(III) ▸ Anko Preview plugin for AnkoComponent layouts ▸ Get it here: http://goo.gl/5CVmAA ▸ Can preview layouts and convert XML to Anko DSL ▸ Can be fiddly to get going with AS, Kotlin plugin versions
  • 50.
    ANKO DSL EXTENDING ANKOSDSL FUNCTIONALITY (I) ▸ Multiple ways to do this: ▸ insert an existing XML layout into an Anko DSL declaration:
 ▸ adding new DSL elements to the language include<View>(R.layout.mylayout) { ... } inline fun ViewManager.customView(theme: Int = 0) = customView(theme) {} inline fun ViewManager.customView(theme: Int = 0, init: CustomView.() -> Unit) = ankoView({ CustomView(it) }, theme, init) inline fun Activity.customView(theme: Int = 0) = customView(theme) {} inline fun Activity.customView(theme: Int = 0, init: CustomView.() -> Unit) = ankoView({ CustomView(it) }, theme, init)
  • 51.
    ANKO DSL EXTENDING ANKOSDSL FUNCTIONALITY (II) ▸ Extending Anko’s DSL to support your own custom view groups is currently rather painful ▸ Essentially it comes down to .lparams (for layout purposes) not being easily accessible ▸ More here: ▸ http://goo.gl/qpb3SL ▸ http://goo.gl/tMHs2c ▸ Fix targeted for Anko 0.9.1
  • 52.
  • 53.
    THE HIDDEN PARTSOF ANKO BUT THERE’S MORE ▸ Intent wrappers for various purposes: e.g. sendSMS(number, [text]) ▸ Intent builders ▸ Service shortcuts ▸ Configuration qualifiers: configuration(screenSize = ScreenSize.LARGE, orientation = Orientation.LANDSCAPE) { … } ▸ Asynchronous tasks ▸ SQLLite
  • 54.
    THE HIDDEN PARTSOF ANKO INTENT WRAPPERS AND SERVICE SHORTCUTS ▸ Anko provides wrappers for commonly used Intents: ▸ makeCall(number), sendSMS(number, text), browse(url) etc. ▸ Shortcuts to Android services: ▸ notificationManager, displayManager, sensorManager etc. ▸ Useful, but both not major features of Anko
  • 55.
    THE HIDDEN PARTSOF ANKO INTENT BUILDERS ▸ Syntactic sugar to cut down the amount of code needed to start a new activity val intent = Intent(this, javaClass<MyActivity>()) intent.putExtra("customerId", 4711) intent.putExtra("country", "NZ") startActivity(intent) startActivity(Intent(this, MyActivity::class.java). putExtra("customerId", 4711).putExtra("country", "NZ")) startActivity<MyActivity>("customerId" to 4711, "country" to "NZ")
  • 56.
    THE HIDDEN PARTSOF ANKO CONFIGURATION QUALIFIERS ▸ “CSS Media Queries for Android” ▸ Screen features: ▸ screenSize, density, orientation, long, 
 nightMode, rightToLeft, smallestWidth ▸ SDK versions: ▸ fromSdk, sdk ▸ Other: ▸ language, uiMode configuration(screenSize = ScreenSize.LARGE, orientation = Orientation.LANDSCAPE) { /* This code will be only executed if the screen is large and its orientation is landscape */ }
  • 57.
    THE HIDDEN PARTSOF ANKO ASYNC DSL ▸ Does anyone enjoy working with AsyncTasks? ▸ Anko: async and asyncResult (return future respectively future with result) async() { val result = PetFindCommand("90210","cat").execute() uiThread { animalList.adapter = AnimalListAdapter(result, object: AnimalListAdapter.ItemClickListener{ override fun invoke(pet:Pet) { toast(pet.name) } } ) } }
  • 58.
    THE HIDDEN PARTSOF ANKO SQLITE (I) ▸ Working with SQLite usually requires a lot of boilerplate code and try/catch- structures, issues around concurrency, dealing with cached code and references etc. ▸ Anko aims to make that easier ▸ Dependency: compile ‘org.jetbrains.anko:anko-sqlite:0.9' ▸ Setup class extending ManagedSQLiteOpenHelper in your code
  • 59.
    THE HIDDEN PARTSOF ANKO SQLITE (II) ▸ database.use ensures DB is opened and closed correctly ▸ Asynchronous use of the DB is possible through Anko’s async DSL ▸ Important: There can still be SQLiteExceptions when handling SQL code - Anko doesn’t abstract those. ▸ Handling of cursors and parsing data via lambdas database.use { createTable("Customer", ifNotExists = true, "id" to INTEGER + PRIMARY_KEY + UNIQUE, "name" to TEXT, "photo" to BLOB) }
  • 60.
    APP STEP 10 -CLICK ON LIST ▸ Adapter/RecyclerView click handler changes ▸ when-statement
  • 61.
    APP STEP 11 -EXCEPTIONS ▸ Exception handler in Anko
  • 62.
    APP STEP 12 -ANKO DSL ▸ Anko layout for main view ▸ Removing layout XML and replacing it with Anko DSL
  • 63.
    APP STEP 13 -ANKO COMPONENTS ▸ Refactoring into Anko component
  • 64.
    APP STEP 14 ▸ Minirefactoring for better testing ▸ jUnit tests in Kotlin
  • 65.
    APP STEP 15 ▸ UsingSpek for BDD testing
  • 66.
    APP IDEAS ▸ Add secondActivity or Fragment to display and edit details ▸ Change layout to ConstraintLayout ▸ Use Kotson instead of Gson ▸ Store data locally ▸ Change RecyclerView to Anko Layout DSL ▸ Use Butterknife instead of Kotterknife ▸ Write some proper tests ▸ Try Android integration tests
  • 67.
  • 68.
  • 69.
    RESOURCES RESOURCES ▸ Kotlin: http://kotlinlang.org ▸Anko: https://github.com/Kotlin/anko ▸ Kotter Knife: https://github.com/JakeWharton/kotterknife ▸ Spek: http://jetbrains.github.io/spek/ ▸ Kotson: https://github.com/SalomonBrys/Kotson
  • 70.
    RESOURCES GET IN TOUCH KaiKoenig Email: kai@ventego-creative.co.nz Twitter: @AgentK Kate Henderson Email: hi@kate.nz Twitter: @Mistyepd