Share
Embed
Kotlin + Android
Brief overview of Kotlin syntax and features for GDG Lviv Android Spring Barcamp 2016
Dmytro Danylyk
April 21, 2016
Transcript
128 slides
-
Statically typed programming language for the JVM, Android and the
browser 100% interoperable with Java™ -
How to add Kotlin to your project? 2. Declare dependencies
buildscript { dependencies { classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } } apply plugin: 'kotlin-android' dependencies { compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" } -
How to add Kotlin to your project? 2. Declare dependencies
buildscript { dependencies { classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } } apply plugin: 'kotlin-android' dependencies { compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" } -
What does it look like? val a: Int = 1
Read only variable -
What does it look like? val a: Int = 1
val b = 1 Int type is inferred -
What does it look like? val a: Int = 1
val b = 1 var c: Int Mutable variable -
What does it look like? val a: Int = 1
val b = 1 var c: Int c = 2 -
What does it look like? val a: Int = 1
val b = 1 var c: Int c = 2 val date = Date() print(date.time) Instances of class -
What does it look like? class Main { fun printSum(a:
Int, b: Int) { print(a + b) } fun returnSum(a: Int, b: Int): Int { return a + b } } Class name -
What does it look like? class Main { fun printSum(a:
Int, b: Int) { print(a + b) } fun returnSum(a: Int, b: Int): Int { return a + b } } -
What does it look like? class Main { fun printSum(a:
Int, b: Int) { print(a + b) } fun returnSum(a: Int, b: Int): Int { return a + b } } Function name -
What does it look like? class Main { fun printSum(a:
Int, b: Int) { print(a + b) } fun returnSum(a: Int, b: Int): Int { return a + b } } Function arguments -
What does it look like? class Main { fun printSum(a:
Int, b: Int) { print(a + b) } fun returnSum(a: Int, b: Int): Int { return a + b } } Return type -
Kotlin Features String templates Properties Lambdas Data class Smart cast
Null safety Default values for function parameters Lazy property Extension Functions Single-expression functions When expression let, apply, use, with Collections Kotlin Android Extensions Plugin Anko -
String templates val query = "Kotlin" val language = "en"
val url = "https://www.google.com.ua/#q=$query&language=$language" -
String templates val query = "Kotlin" val language = "en"
val url = "https://www.google.com.ua/#q=$query&language=$language" -
String templates val query = "Kotlin" val language = "en"
val url = "https://www.google.com.ua/#q=$query&language=$language" > https://www.google.com.ua/#q=Kotlin&language=en -
Properties class User { var name: String? = null var
age: Int? = null } -
Properties class User { var name: String? = null var
age: Int? = null } val user = User() user.name = "John" user.age = 24 print("User name:${user.name}") -
Properties class User { var name: String? = null var
age: Int? = null set(value) { if (value >= 0) field = value } } -
Lambdas button.setOnClickListener(object : View.OnClickListener { override fun onClick(v: View?) {
toast("Button clicked") } }) -
Lambdas button.setOnClickListener(object : View.OnClickListener { override fun onClick(v: View?) {
toast("Button clicked") } }) An anonymous class -
Lambdas button.setOnClickListener({ toast("Button clicked") }) Lambda is last parameter, can
be moved out of the parentheses -
Lambdas button.setOnClickListener() { toast("Button clicked") } Lambda is the only
parameter, parentheses are optional -
Data class • getters, setters • equals()/hashCode() • toString() of
the form "User(name=John, age=42)" • copy() function Nothing, just hold data What it does? What it provides? -
Data class data class User(val name: String, val age: Int)
val user = User("Dmytro", 24) print(user) > User(name=Dmytro, age=24) -
Smart cast fun demo(x: Any) { if (x is String)
{ print(x.length) } else if (x is Int) { print(x * x) } } -
Smart cast fun demo(x: Any) { if (x is String)
{ print(x.length) } else if (x is Int) { print(x * x) } } x is automatically cast to String -
Smart cast fun demo(x: Any) { if (x is String)
{ print(x.length) } else if (x is Int) { print(x * x) } } x is automatically cast to Int -
Smart cast fun demo(x: Any) { if (x is String)
{ print(x.length) } else if (x is Int) { print(x * x) } } -
Null safety var name: String = null override fun onCreate(savedInstanceState:
Bundle?) { super.onCreate(savedInstanceState) name = savedInstanceState.getString("name") } -
Null safety var name: String = null override fun onCreate(savedInstanceState:
Bundle?) { super.onCreate(savedInstanceState) name = savedInstanceState.getString("name") } Compilation error, non null variable -
Null safety var name: String? = null override fun onCreate(savedInstanceState:
Bundle?) { super.onCreate(savedInstanceState) name = savedInstanceState.getString("name") } -
Null safety var name: String? = null override fun onCreate(savedInstanceState:
Bundle?) { super.onCreate(savedInstanceState) name = savedInstanceState.getString("name") } Compilation error, argument may be null -
Null safety var name: String? = null override fun onCreate(savedInstanceState:
Bundle?) { super.onCreate(savedInstanceState) name = savedInstanceState?.getString("name") } -
Null safety var name: String? = null override fun onCreate(savedInstanceState:
Bundle?) { super.onCreate(savedInstanceState) name = savedInstanceState?.getString("name") } -
Default values for function parameters Function parameters can have default
values, which are used when a corresponding argument is omitted. This allows for a reduced number of overloads compared to other languages. -
Default values for function parameters fun query(table: String, columns: Array<String>,
selection: String?, selectionArgs : Array<String>?, orderBy: String?): Cursor { ... } // function call query("USERS", arrayOf("ID", "NAME"), null, null, "NAME") -
Default values for function parameters fun query(table: String, columns: Array<String>,
selection: String? = null, selectionArgs : Array<String>? = null, orderBy: String? = null): Cursor { ... } // function call query("USERS", arrayOf("ID", "NAME"), null, null, "NAME") Default value -
Default values for function parameters fun query(table: String, columns: Array<String>,
selection: String? = null, selectionArgs : Array<String>? = null, orderBy: String? = null): Cursor { ... } // function call query("USERS", arrayOf("ID", "NAME"), null, null, "NAME") -
Default values for function parameters fun query(table: String, columns: Array<String>,
selection: String? = null, selectionArgs : Array<String>? = null, orderBy: String? = null): Cursor { ... } // function call query("USERS", arrayOf("ID", "NAME"), null, null, orderBy = "NAME") Named argument -
Default values for function parameters fun query(table: String, columns: Array<String>,
selection: String? = null, selectionArgs : Array<String>? = null, orderBy: String? = null): Cursor { ... } // function call query("USERS", arrayOf("ID", "NAME"), null, null, orderBy = "NAME") Not need -
Default values for function parameters fun query(table: String, columns: Array<String>,
selection: String? = null, selectionArgs : Array<String>? = null, orderBy: String? = null): Cursor { ... } // function call query("USERS", arrayOf("ID", "NAME"), orderBy = "NAME") -
Lazy property val preference = getSharedPreferences("pref") override fun onCreate(savedInstanceState: Bundle?)
{ super.onCreate(savedInstanceState) val username = preference.getString("username") } -
Lazy property val preference = getSharedPreferences("pref") override fun onCreate(savedInstanceState: Bundle?)
{ super.onCreate(savedInstanceState) val username = preference.getString("username") } Crash, require context -
Lazy property val preference by lazy { getSharedPreferences("pref") } override
fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val username = preference.getString("username") } Won’t be executed until the property is first used -
Lazy property val preference by lazy { getSharedPreferences("pref") } override
fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val username = preference.getString("username") } -
Extension Functions Extensions do not actually modify classes they extend.
By defining an extension, you do not insert new members into a class, but merely make new functions callable with the dot-notation on instances of this class. Provides the ability to extend a class with new functionality without having to inherit from the class. What it does? How? -
Single-expression functions When a function returns a single expression, the
curly braces can be omitted and the body is specified after a = symbol. -
Single-expression functions fun createUrl(search: String): String { return "www.google.com.ua/#q=$search" }
Function returns a single expression -
Single-expression functions fun createUrl(search: String): String = "www.google.com.ua/#q=$search" Curly braces
can be omitted body is specified after a = symbol -
When expression When expression is similar to switch/case in Java,
but far more powerful. -
When expression when (argument) { match1 -> fun1() match2 ->
fun2() else -> fun3() } -
When expression when (argument) { match1 -> fun1() match2 ->
fun2() else -> fun3() } Can be anything -
When expression when (argument) { match1 -> fun1() match2 ->
fun2() else -> fun3() } Can be anything -
When expression var result: Int = when (argument) { match1
-> fun1() match2 -> fun2() else -> fun3() } Can return result -
When expression var result: Int = when (argument) { match1
-> fun1() match2 -> fun2() else -> fun3() } -
When expression override fun onCreateViewHolder(g: ViewGroup, type: Int) { when
(type) { TYPE_TITLE -> TitleViewHolder(g) TYPE_DESCRIPTION -> DescriptionViewHolder(g)) } return null } -
When expression override fun onCreateViewHolder(g: ViewGroup, type: Int) { when
(type) { TYPE_TITLE -> TitleViewHolder(g) TYPE_DESCRIPTION -> DescriptionViewHolder(g)) } return null } Can be placed after a = symbol -
When expression override fun onCreateViewHolder(g: ViewGroup, type: Int) = when
(type) { TYPE_TITLE -> TitleViewHolder(g) TYPE_DESCRIPTION -> DescriptionViewHolder(g)) else -> null } -
When expression override fun onCreateViewHolder(g: ViewGroup, type: Int) = when
(type) { TYPE_TITLE -> TitleViewHolder(g) TYPE_DESCRIPTION -> DescriptionViewHolder(g) else -> null } -
When expression override fun getItemViewType(index: Int) = when (dataList[index]) {
is Title -> TYPE_TITLE is Description -> TYPE_DESCRIPTION else -> TYPE_UNDEFINED } -
When expression override fun getItemViewType(index: Int) = when (dataList[index]) {
is Title -> TYPE_TITLE is Description -> TYPE_DESCRIPTION else -> TYPE_UNDEFINED } Type checks possible -
When expression override fun getItemViewType(index: Int) = when (dataList[index]) {
is Title -> TYPE_TITLE is Description -> TYPE_DESCRIPTION else -> TYPE_UNDEFINED } -
When expression override fun onBindViewHolder(viewHolder: ViewHolder, index: Int) { val
displayable: Displayable = dataList[index] when (displayable) { is Title -> initTitle(viewHolder, displayable) is Description -> initDescription(viewHolder, displayable) } } -
When expression override fun onBindViewHolder(viewHolder: ViewHolder, index: Int) { val
displayable: Displayable = dataList[index] when (displayable) { is Title -> initTitle(viewHolder, displayable) is Description -> initDescription(viewHolder, displayable) } } Smart cast -
When expression override fun onBindViewHolder(viewHolder: ViewHolder, index: Int) { val
displayable: Displayable = dataList[index] when (displayable) { is Title -> initTitle(viewHolder, displayable) is Description -> initDescription(viewHolder, displayable) } } -
let, apply, use, with Higher-order functions - function that takes
functions as parameters, or returns a function. -
let (scope function) /** * Calls the specified function [block]
with `this` value as * its argument and returns its result. */ public inline fun <T, R> T.let(block: (T) -> R): R = block(this) -
use (try with resources function) /** * Executes the given
[block] function on this resource and then * closes it down correctly whether an exception is thrown or not. */ public inline fun <T : Closeable, R> T.use(block: (T) -> R): R { var closed = false try { return block(this) } catch (e: Exception) { // ommitted } finally { if (!closed) { close() } } } -
use fun countUsers(): Long { val database = openDatabase() val
result = database.count("users") database.close() return result } -
with /** * Calls the specified function [block] with the
given [receiver] * as its receiver and returns its result. */ public inline fun <T, R> with(receiver: T, block: T.() -> R): R = receiver.block() -
apply /** * Calls the specified function [block] with `this`
value as its receiver * and returns `this` value. */ public inline fun <T> T.apply(block: T.() -> Unit): T { block(); return this } -
apply fun makeDir(path: String): File { val result: File =
File(path) result.mkdirs() return result } -
Collections val numbers: MutableList<Int> = mutableListOf(1, 2, 3) numbers.add(1) val
numbers2: List<Int> = listOf(1, 2, 3) numbers2.add(1) No such method -
Collections mutableListOf(1, null, 2, null, 3, 4, 5, 6, 7,
8, 9) .filterNotNull() .filter { it % 2 == 0 } .sortedDescending() > [1, null, 2, null, 3, 4, 5, 6, 7, 8, 9] -
Collections mutableListOf(1, null, 2, null, 3, 4, 5, 6, 7,
8, 9) .filterNotNull() .filter { it % 2 == 0 } .sortedDescending() > [1, 2, 3, 4, 5, 6, 7, 8, 9] -
Collections mutableListOf(1, null, 2, null, 3, 4, 5, 6, 7,
8, 9) .filterNotNull() .filter { it % 2 == 0 } .sortedDescending() > [2, 4, 6, 8] -
Collections mutableListOf(1, null, 2, null, 3, 4, 5, 6, 7,
8, 9) .filterNotNull() .filter { it % 2 == 0 } .sortedDescending() > [8, 6, 4, 2] -
Collections getOrElse() find() filter() filterNot() filterNotNull() flatMap() take() takeLast() sortBy()
sortByDescending() groupBy() map() mapNotNull() all() any() maxBy() minBy() minWith() sumBy() zip() ... -
Kotlin Android Extensions Plugin Adds a hidden caching function and
a field inside each Kotlin Activity. Provides reference to all layout views (which have id’s) with single line of code. What it does? How? -
Kotlin Android Extensions Plugin buildscript { dependencies { classpath "org.jetbrains.kotlin:kotlin-android-extensions:$kotlin_version"
} } apply plugin: 'kotlin-android-extensions' -
Kotlin Android Extensions Plugin // R.layout.activity_main import kotlinx.android.synthetic.main.activity_main.* public class
MyActivity : Activity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) txtTitle.setText("Hello, Kotlin!") btnHello.setOnClickListener {...} } } -
Kotlin Android Extensions Plugin // R.layout.activity_main import kotlinx.android.synthetic.main.activity_main.* public class
MyActivity : Activity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) txtTitle.setText("Hello, Kotlin!") btnHello.setOnClickListener {...} } } -
Kotlin Android Extensions Plugin // R.layout.activity_main import kotlinx.android.synthetic.main.activity_main.* public class
MyActivity : Activity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) txtTitle.setText("Hello, Kotlin!") btnHello.setOnClickListener {...} } } Instead of findView(R.id.txtTitle) -
Kotlin Android Extensions Plugin // R.layout.activity_main import kotlinx.android.synthetic.main.activity_main.* public class
MyActivity : Activity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) txtTitle.setText("Hello, Kotlin!") btnHello.setOnClickListener {...} } } -
Anko Kotlin library from JetBrains which provide API to make
Android application development faster and easier. What it does? -
Anko alert("Santa", "You were a good boy?") { positiveButton("Yes") {
toast("You are now in GOOD list") } negativeButton("No") { toast("You are now in BAD list") } }.show() val countries = listOf("Ukraine", "USA", "UK",) selector("Where are you from?", countries) { i -> toast("So you're living in ${countries[i]}, right?") } -
Anko async() { // long background task uiThread { //
won't be executed if isFinishing() is true toolbar.title = "Done" } } -
Anko database.use { createTable("Customer", ifNotExists = true, "_id" to INTEGER
+ PRIMARY_KEY + UNIQUE, "name" to TEXT, "photo" to BLOB) } -
Resources www.kotlinlang.org/docs/reference www.try.kotlinlang.org www.antonioleiva.com/kotlin - documentation - online compiler +
exercises - kotlin blog (by Antonio Leiva)