Slide 1

Slide 1 text

Kotlin for Android Developers Michael Evans @m_evans10 +MichaelEvans michaelevans.org

Slide 2

Slide 2 text

Kotlin for Android Developers Michael Evans LivingSocial @m_evans10

Slide 3

Slide 3 text

Kotlin for Android Developers Michael Evans LivingSocial @m_evans10

Slide 4

Slide 4 text

Kaitlin for Android Developers Michael Evans LivingSocial @m_evans10

Slide 5

Slide 5 text

Kotlin? • Statically Typed • Developed by JetBrains • 100% interoperable with Java

Slide 6

Slide 6 text

Why Kotlin? • Mutability problems • General verbosity • No control over platform types

Slide 7

Slide 7 text

Nullability

Slide 8

Slide 8 text

Nullability I call it my billion-dollar mistake. It was the invention of the null reference in 1965 […] This has led to innumerable errors, vulnerabilities, and system crashes, which have probably caused a billion dollars of pain and damage in the last forty years.

Slide 9

Slide 9 text

Why Kotlin? • Type inference • Lambdas • Null safety • Smart casts • String templates • Higher order functions • Extension functions • Data classes • Default Values

Slide 10

Slide 10 text

Getting Started

Slide 11

Slide 11 text

Getting Started buildscript {
 repositories {
 mavenCentral()
 }
 dependencies {
 classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.0.3"
 }
 }
 
 apply plugin: 'kotlin'
 
 dependencies {
 compile "org.jetbrains.kotlin:kotlin-stdlib:1.0.3" }


Slide 12

Slide 12 text

Getting Started buildscript {
 repositories {
 mavenCentral()
 }
 dependencies {
 classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.0.3"
 }
 }
 
 apply plugin: 'kotlin'
 
 dependencies {
 compile "org.jetbrains.kotlin:kotlin-stdlib:1.0.3" }


Slide 13

Slide 13 text

Syntax

Slide 14

Slide 14 text

fun sum(a: Int, b: Int): Int {
 return a + b
 } Syntax

Slide 15

Slide 15 text

fun sum(a: Int, b: Int): Int {
 return a + b
 } Syntax

Slide 16

Slide 16 text

Syntax fun sum(a: Int, b: Int): Int {
 return a + b
 }

Slide 17

Slide 17 text

fun sum(a: Int, b: Int): Int {
 return a + b
 } Syntax

Slide 18

Slide 18 text

fun sum(a: Int, b: Int) = a + b
 Syntax

Slide 19

Slide 19 text

Defining Variables final int a = 1;
 
 
 int x = 5;

Slide 20

Slide 20 text

Defining Variables val a: Int = 1
 val b = 1
 
 var x = 5
 x += 1 final int a = 1;
 
 
 int x = 5;

Slide 21

Slide 21 text

Defining Variables val a: Int = 1
 val b = 1
 
 var x = 5
 x += 1 final int a = 1;
 
 
 int x = 5;

Slide 22

Slide 22 text

Properties public class Person {
 
 private String name;
 
 public String getName() {
 return name;
 }
 
 public void setName(String name) {
 this.name = name;
 }
 }

Slide 23

Slide 23 text

Properties var person = Person()
 person.name = "Mike"
 val name = person.name class Person {
 
 var name: String = "Ryan"
 }

Slide 24

Slide 24 text

String Templates var person = Person("Mike")
 
 println("Hello my name is ${person.name}")

Slide 25

Slide 25 text

Nullability Make NullPointerException happen at compile time, not runtime.

Slide 26

Slide 26 text

val string: String = "Mike"
 val another: String = null // does not compile
 
 val nullable: String? = null // ok Nullability

Slide 27

Slide 27 text

Nullability if (files != null) {
 return files.size
 }

Slide 28

Slide 28 text

Nullability println(person?.name)
 
 val email = data["email"] ?: "[email protected]"
 
 data?.let {
 // execute this block if not null
 
 println(files!!.size)

Slide 29

Slide 29 text

Nullability println(person?.name?.length)
 
 val email = data["email"] ?: "[email protected]"
 
 data?.let {
 // execute this block if not null
 
 println(files!!.size)

Slide 30

Slide 30 text

Nullability println(person?.name?.length)
 
 val email = data["email"] ?: "[email protected]"
 
 data?.let {
 // execute this block if not null
 
 println(files!!.size)

Slide 31

Slide 31 text

Nullability println(person?.name?.length)
 
 val email = data["email"] ?: "[email protected]" 
 println(files!!.size)

Slide 32

Slide 32 text

fun toast(message: String, length: Int = Toast.LENGTH_SHORT) {
 Toast.makeText(this, message, length).show()
 } Default Values

Slide 33

Slide 33 text

fun toast(message: String, length: Int = Toast.LENGTH_SHORT) {
 Toast.makeText(this, message, length).show()
 } toast("Hello")
 toast("Hello", Toast.LENGTH_LONG)
 toast("Hello", length = Toast.LENGTH_LONG) Default Values

Slide 34

Slide 34 text

Extension Functions fun List.swap(index1: Int, index2: Int) {
 val tmp = this[index1]
 this[index1] = this[index2]
 this[index2] = tmp
 }

Slide 35

Slide 35 text

fun Activity.toast(message: CharSequence, duration: Int = Toast.LENGTH_SHORT) {
 Toast.makeText(this, message, duration).show()
 } fun List.swap(index1: Int, index2: Int) {
 val tmp = this[index1]
 this[index1] = this[index2]
 this[index2] = tmp
 } Extension Functions

Slide 36

Slide 36 text

{ it.isEmpty() } 
 { it.length == 10 } 
 { isPalindrome(it) } Function Expressions

Slide 37

Slide 37 text

{ it.isEmpty() } 
 { it.length == 10 } 
 { isPalindrome(it) } Function Expressions

Slide 38

Slide 38 text

{ it.isEmpty() } 
 { it.length == 10 } 
 { isPalindrome(it) } Function Expressions

Slide 39

Slide 39 text

val isEmpty: (String) -> Boolean = { it.isEmpty() } 
 val exactly10: (String) -> Boolean = { it.length == 10 } 
 val palindrome: (String) -> Boolean = { isPalindrome(it) } Function Expressions

Slide 40

Slide 40 text

fun List.filter(predicate: (T) -> Boolean): List {
 // ...
 } Higher order functions

Slide 41

Slide 41 text

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

Slide 42

Slide 42 text

fun List.filter(predicate: (T) -> Boolean): List {
 // ...
 } Higher order functions val names = listOf("Mike", "John", "Bob")
 names.filter { it == "Mike" } // ["Mike"]
 names.filter(palindrome) // ["Bob"]

Slide 43

Slide 43 text

Examples

Slide 44

Slide 44 text

Extension Functions Picasso.with(imageView.getContext())
 .load(imageUrl)
 .into(imageView);

Slide 45

Slide 45 text

Extension Functions fun ImageView.load(url: String) {
 Picasso.with(context).load(url).into(this)
 }

Slide 46

Slide 46 text

Extension Functions fun ImageView.load(url: String) {
 Picasso.with(context).load(url).into(this)
 } imageView.load("http://...")

Slide 47

Slide 47 text

inline fun supportsLollipop(code: () -> Unit) {
 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
 code.invoke()
 }
 } Inline Functions

Slide 48

Slide 48 text

supportsLollipop {
 getWindow().setStatusBarColor(Color.BLACK)
 } inline fun supportsLollipop(code: () -> Unit) {
 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
 code.invoke()
 }
 } Inline Functions

Slide 49

Slide 49 text

public class ContactsAdapter extends RecyclerView.Adapter {
 interface ContactClickListener {
 void onContactClicked(Contact contact);
 }

Slide 50

Slide 50 text

public class ContactsAdapter extends RecyclerView.Adapter {
 interface ContactClickListener {
 void onContactClicked(Contact contact);
 } recycler.setAdapter(new ContactsAdapter(contacts, new ContactsAdapter.ContactClickListener() {
 @Override
 public void onContactClicked(ContactsAdapter.Contact contact) {
 
 }
 }));

Slide 51

Slide 51 text

recycler.adapter = ContactsAdapter(contacts) {
 navigateToDetail(it)
 }
 
 class ContactsAdapter(val contacts: List,
 val listener: (Contact) -> Unit)
 
 itemView.setOnClickListener { listener(contact) }

Slide 52

Slide 52 text

recycler.adapter = ContactsAdapter(contacts) {
 navigateToDetail(it)
 }
 
 class ContactsAdapter(val contacts: List,
 val listener: (Contact) -> Unit)
 
 itemView.setOnClickListener { listener(contact) }

Slide 53

Slide 53 text

recycler.adapter = ContactsAdapter(contacts) {
 navigateToDetail(it)
 }
 
 class ContactsAdapter(val contacts: List,
 val listener: (Contact) -> Unit)
 
 itemView.setOnClickListener { listener(contact) }

Slide 54

Slide 54 text

Extension Function Expressions

Slide 55

Slide 55 text

Extension Function Expressions SharedPreferences.Editor editor = getSharedPreferences("prefs", 0).edit();
 editor.putString("this", "that");
 editor.apply();

Slide 56

Slide 56 text

inline fun SharedPreferences.edit( func: SharedPreferences.Editor.() -> Unit) {
 val editor = edit()
 editor.func()
 editor.apply()
 }
 
 Extension Function Expressions

Slide 57

Slide 57 text

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

Slide 58

Slide 58 text

inline fun SharedPreferences.edit( func: SharedPreferences.Editor.() -> Unit) {
 val editor = edit()
 editor.func()
 editor.apply()
 }
 
 fun SharedPreferences.Editor.set(pair: Pair) =
 putString(pair.first, pair.second) Extension Function Expressions

Slide 59

Slide 59 text

preferences.edit {
 set("foo" to "bar")
 set("fizz" to "buzz")
 remove("username")
 } Extension Function Expressions

Slide 60

Slide 60 text

Libraries

Slide 61

Slide 61 text

verticalLayout {
 padding = dip(30)
 editText {
 hint = "Name"
 textSize = 24f
 }
 editText {
 hint = "Password"
 textSize = 24f
 }
 button("Login") {
 textSize = 26f
 }
 } Anko

Slide 62

Slide 62 text

apply plugin: 'kotlin-android-extensions' import kotlinx.android.synthetic.main.activity_main.* … textView.setText("Hello, world!") Kotlin Extensions for Android

Slide 63

Slide 63 text

Getting started?

Slide 64

Slide 64 text

Java Interoperability

Slide 65

Slide 65 text

Java Interoperability class Person {
 private String name;
 
 public void setName(String name) {
 this.name = name;
 }
 }

Slide 66

Slide 66 text

var person = Person()
 person.name = "name" Java Interoperability class Person {
 private String name;
 
 public void setName(String name) {
 this.name = name;
 }
 }

Slide 67

Slide 67 text

Java Interoperability - Extensions

Slide 68

Slide 68 text

// com/example/util/DateExtensions.kt
 fun Date.isTuesday() = day == 2
 
 // com/example/util/DateExtensionsKt.java
 static boolean isTuesday(Date date) {
 return date.getDay() == 2;
 } Java Interoperability - Extensions

Slide 69

Slide 69 text

// com/example/util/DateExtensions.kt
 fun Date.isTuesday() = day == 2
 
 // com/example/util/DateExtensionsKt.java
 static boolean isTuesday(Date date) {
 return date.getDay() == 2;
 } Java Interoperability - Extensions

Slide 70

Slide 70 text

// com/example/util/DateExtensions.kt @file:JvmName("DateUtils") fun Date.isTuesday() = day == 2
 
 // com/example/util/DateUtils.java
 static boolean isTuesday(Date date) {
 return date.getDay() == 2;
 } Java Interoperability - Extensions

Slide 71

Slide 71 text

Implement Tests in Kotlin

Slide 72

Slide 72 text

Data Classes class Person {
 private String name;
 private int age;
 
 public String getName() {
 return name;
 }
 
 public int getAge() {
 return age;
 }
 }

Slide 73

Slide 73 text

Data Classes @Override public boolean equals(Object o) {
 if (this == o) return true;
 if (o == null || getClass() != o.getClass()) return false;
 
 Person person = (Person) o;
 
 if (age != person.age) return false;
 return name != null ? name.equals(person.name) : person.name == null;
 }
 
 @Override public int hashCode() {
 int result = name != null ? name.hashCode() : 0;
 result = 31 * result + age;
 return result;
 }
 
 @Override public String toString() {
 return super.toString();
 }
 }

Slide 74

Slide 74 text

Data Classes data class Person(val name: String, val age: Int)

Slide 75

Slide 75 text

Convert Java File to Kotlin Kotlin Scripts for Gradle

Slide 76

Slide 76 text

More Info • https://kotlinlang.org • Koans • https://kotlinlang.org/docs/tutorials/koans.html • https://leanpub.com/kotlin-for-android-developers

Slide 77

Slide 77 text

Questions? Michael Evans @m_evans10 +MichaelEvans michaelevans.org

Slide 78

Slide 78 text

Questions? Michael Evans @m_evans10 +MichaelEvans michaelevans.org STICKERS!