77
Practical tips for building apps with kotlin Adit Lal | @aditlal

Practical tips for building apps with kotlin

Embed Size (px)

Citation preview

Page 1: Practical tips for building apps with kotlin

Practical tips for building apps with kotlin

Adit Lal | @aditlal

Page 2: Practical tips for building apps with kotlin

Agenda

What is Kotlin?

Perfect for Android

Migration guide

Best Practices

Summary - QnABuilding with kotlin

Page 3: Practical tips for building apps with kotlin

100 % interoperable with Java

Developed by JetBrains

Background

Page 4: Practical tips for building apps with kotlin

What is Kotlin?

Statically typed programming language for the JVM, Android and the browser

Page 5: Practical tips for building apps with kotlin
Page 6: Practical tips for building apps with kotlin

OOP language

with functional

aspects

Modern and powerful language

Safe concise & readable

code

First class tool support

What is Kotlin?

Page 7: Practical tips for building apps with kotlin

Kotlin

• Null safety

• Conciseness

• Lambdas

• Higher order functions

• Mutability protection

• Static typing + Smart Casts

We will cover :

Page 8: Practical tips for building apps with kotlin

Kotlin

Kotlin works on same byte code

Page 9: Practical tips for building apps with kotlin

Kotlin - Syntax

• Types follow variable/function names

• Functions start with fun keyword

• Default constructor in class signature

• Semicolons not required

Page 10: Practical tips for building apps with kotlin

Kotlin - Syntax

private fun sum(first: Int , second: Int): Int { return first + second }

Access modifier

Keyword

Function name

Param name Param type

Return type

Page 11: Practical tips for building apps with kotlin

Kotlin - Syntax

// Omit access modifier fun sum(a: Int , b: Int): Int { return a + b } // Inline return fun sum(a: Int , b: Int): Int = a + b

// Omit return type fun sum(a: Int , b: Int) = a + b

Page 12: Practical tips for building apps with kotlin

Kotlin - Syntax

val name: String ="John" // final

var name: String ="John" //Mutable

ex: name= "Johnny"

Two types of variables

val name ="John" // Types are auto-inferred

Page 13: Practical tips for building apps with kotlin

Kotlin - Syntax

//java String sName = person.getSecretName()

//kotlin person.secretName = “Batman” var fName = person.secretName

Page 14: Practical tips for building apps with kotlin

Kotlin - Null Safety

NULLS ARE PART OF THE TYPE SYSTEM

Page 15: Practical tips for building apps with kotlin

Kotlin - Null SafetyTypes default to non-nullable

Mark nullable with the addition of a ?

var a: String = "abc" a = null

var b: String? = "abc" b = null

var l = a.length var l = b.length

// compilation error

// OK

// error: variable 'b' can be null

Page 16: Practical tips for building apps with kotlin

Kotlin - Null Safety

Helpers

Safe accessor  ?

Elvis operator  ?:

Page 17: Practical tips for building apps with kotlin

val toDisplay: String = serverResponse

Kotlin - Null

// if response is null, we'll display a default

message

val toDisplay: String = response ?: defaultMessage

Page 18: Practical tips for building apps with kotlin

Kotlin - Null

// cascading null safety

val maybeName: String? = maybeNullValue?.someProperty?.name

val maybeNullValue: MyValue? = /*..*/

Page 19: Practical tips for building apps with kotlin

Kotlin - Null

// safe operation maybeNullValue?.let { //executed if not null }

val maybeNullValue: MyValue? = /*..*/

Page 20: Practical tips for building apps with kotlin

Casting

if (obj instanceOf MyType) { value = ((MyType)obj).getXValue();

} else { // handle else }

Page 21: Practical tips for building apps with kotlin

Kotlin - Smart casting

if (obj is MyType) { value = obj.x } else { // handle else }

Page 22: Practical tips for building apps with kotlin

Class

// Wont Compileclass Student : Person()

class Person

Page 23: Practical tips for building apps with kotlin

open class Person

Class

//It works nowclass Student : Person()

Page 24: Practical tips for building apps with kotlin

Higher order functions

Functions that can take functions as arguments and also return function as the

output

Page 25: Practical tips for building apps with kotlin

fun <T> forEach(list: List<T>, funcToCall: (T) -> Unit) { for (elm in list) { funcToCall(elm) }

}

val list = listOf("Alice", "Bob", "Claire") forEach(list, ::println) forEach(list, { str -> println(str) })

Higher order functions

Page 26: Practical tips for building apps with kotlin

Kotlin - Features

… and More

• Visibility Modifiers • Companion Objects • Nested, Sealed Classes • Generics • Coroutines • Operator overloading • Exceptions • Annotations • Reflection • and more

Page 27: Practical tips for building apps with kotlin

Kotlin - Features

… and Even More

• Infix extension methods • Interfaces • Interface Delegation • Property Delegation • Destructuring • Safe Singletons • Init blocks • Enums • Multiline Strings • Tail recursion

Page 28: Practical tips for building apps with kotlin

Perfect for

• Versatile language

• Complete interop with Java

• Compact runtime

• Enhance development speed with

less code

Page 29: Practical tips for building apps with kotlin

“But I’m comfortable and experienced with Java.”

Common Concerns

Page 30: Practical tips for building apps with kotlin

“I don’t want to convert my entire codebase to a new language.”

Common Concerns

Page 31: Practical tips for building apps with kotlin

•Compiled to byte code (like Java)

•No impact on performance

•Some Kotlin code faster

•Lambdas that can be inlined

•Built-in operations faster than DIY implementations

Kotlin

Page 32: Practical tips for building apps with kotlin

How to migrate

Start in small steps - Convert a Java / Android app (side project)

Try the kotlin plugin converter

Understand how code is converted from Java to Kotlin

Experiment with kotlin features and tweak code

Page 33: Practical tips for building apps with kotlin

•Add Gradle dependencies (plugin, runtime, etc.)

•Start writing .kt files instead of .java ones

•No need to migrate everything at once

•Kotlin classes can co-exist with Java ones

• IntelliJ has a Java-to-Kotlin converter

•Not perfect but good start

• Works with pasted code

Try kotlin

Page 34: Practical tips for building apps with kotlin

Java>Kotlin

Page 35: Practical tips for building apps with kotlin

class HomeActivity : AppCompatActivity() { override fun onCreate(b: Bundle?) { super.onCreate(b) setContentView(R.layout.activity_main) val view = findViewById<View>(R.id.view) view.alpha = 1f } }

Android & Kotlin

Page 36: Practical tips for building apps with kotlin

class HomeActivity : AppCompatActivity() { override fun onCreate(b: Bundle?) { super.onCreate(b) setContentView(R.layout.activity_main) val view = findViewById<View>(R.id.view) view.alpha = 1f } }

Android & Kotlin

Page 37: Practical tips for building apps with kotlin

• View binding (like Butter Knife) • No instance variables required • How?

Android extensionsapply plugin: 'kotlin-android-extensions'

• Import synthetic layout import kotlinx.android.synthetic.main..*

• Use view by ID E.g. toolbar.title = "Home"

• Under the hood: synthetic calls replaced by functions

Page 38: Practical tips for building apps with kotlin

class HomeActivity : AppCompatActivity() { override fun onCreate(b: Bundle?) { super.onCreate(b) setContentView(R.layout.activity_main) val view = findViewById<View>(R.id.view) view.alpha = 1f } }

Android & Kotlin

Page 39: Practical tips for building apps with kotlin

Android extensions

class HomeActivity : AppCompatActivity() { override fun onCreate(b: Bundle?) { super.onCreate(b) setContentView(R.layout.activity_main) val view = findViewById<View>(R.id.view) view.alpha = 1f } }

Page 40: Practical tips for building apps with kotlin

Android extensions

import kotlinx.android.synthetic.activity_main.*

class HomeActivity : AppCompatActivity() { override fun onCreate(b: Bundle?) { super.onCreate(b) setContentView(R.layout.activity_main) view.alpha = 1f } }

Page 41: Practical tips for building apps with kotlin

view.setOnClickListener{ toast(“Hello") }

Concise

view.setOnClickListener(object : View.OnClickListener { override fun onClick(v: View?) { toast("Hello") } })

view.setOnClickListener{ view -> doSomethingWithView() }

Page 42: Practical tips for building apps with kotlin

Concise

fun Context.inflate( res:Int, parent:ViewGroup? = null) : View {

return LayoutInflater.from(this) .inflate(res, parent, false) }

activity.inflate(R.layout.my_layout, container) //Fragment

Page 43: Practical tips for building apps with kotlin

public class Person {

private String name; private String surname; private String id;

/* Setters and getters - 20 lines */

@Override public boolean equals(Object o) { //another few lines here }

@Override public int hashCode() { //some more lines }

@Override public String toString() { //some more } }

Data classes

Page 44: Practical tips for building apps with kotlin

Kotlin -

data class Person( val name: String, var surname: String = "", val id: String )

Data classes

Page 45: Practical tips for building apps with kotlin

Kotlin - Data classes

equals() & hashCode()

toString()

copy() function

Page 46: Practical tips for building apps with kotlin

fun evaluateObject(obj: Any): String { return when(obj){ is String -> "Ahoy !!" is Int -> "Lucky no is $obj" else -> "Object is in space" } }

KotlinWhen expression

Page 47: Practical tips for building apps with kotlin

// Java if(name.toLowerCase().contains(str)) {

... }

Android

Page 48: Practical tips for building apps with kotlin

// Kotlin if (name.contains(str, true)) {

... }

Android

Page 49: Practical tips for building apps with kotlin

for (i in 1..100) { ... } for (i in 0 until 100) { ... } for (i in 2..10 step 2) { ... } for (i in 10 downTo 1) { ... } if (x in 1..10) { ... }

Android Kotlin tricks

Page 50: Practical tips for building apps with kotlin

fun ImageView.loadUrl(url: String) { Glide.with(context).load(url).into(this) }

ImageLoadingExtensions.kt

Android

//Then ivAvatar.loadUrl("some_fancy_url")

Page 51: Practical tips for building apps with kotlin

Utils

fun View.visible() { visibility = View.VISIBLE } fun View.gone() { visibility = View.GONE }

//call view.visible()

Page 52: Practical tips for building apps with kotlin

Utils

fun View.setHeight(height: Int) { val params = layoutParams params.height = height layoutParams = params }

//call tvTotalPrice.setHeight(50)

Page 53: Practical tips for building apps with kotlin

fun Activity.showOnUiThread(init: Activity.() -> Unit) : Activity { if (!isFinishing) {

runOnUiThread { init()

} } return this

}

Utils

//call showOnUiThread(updateUIWithNewData())

Page 54: Practical tips for building apps with kotlin

fun Activity.hideKeyboard(): Boolean { val view = currentFocus view?.let { val imm = getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager return imm.hideSoftInputFromWindow(view.windowToken, HIDE_NOT_ALWAYS) } return false }

Utils

Page 55: Practical tips for building apps with kotlin

Adopting kotlin into android code

Page 56: Practical tips for building apps with kotlin

class MyActivity : AppCompactActivity(){ // wont be init here lateinit var obj: CustomObject

override fun onCreate(...){ obj = intent.getExtras().get("key") // this will init the variable } }

lateinit Modifier

Page 57: Practical tips for building apps with kotlin

When to use lateinit

If you’re variable is mutable

If you’re sending a object from another component/ screen — ex Intent extras

lateinit Modifier

Page 58: Practical tips for building apps with kotlin

val myUtil by lazy { SomeUtil(parameter1, parameter2) }

Lazy Initialisation

Page 59: Practical tips for building apps with kotlin

val hashMap = HashMap<String, String>() hashMap.put("keyA", "valueA") hashMap.put("keyB", "valueB") hashMap.put("keyC", "valueC")

//change to val map = mapOf( "keyA" to "valueA", "keyB" to "valueB", "keyC" to "valueC" )

Kotlin

Page 60: Practical tips for building apps with kotlin

fun listItemsToDisplay(): List<ListItem> { return listOf(users) + friends() + recentSearches() }

Kotlin

Page 61: Practical tips for building apps with kotlin

fun parseResponse(response: Response?) = when (response?.code()) { null -> throw HTTPException(“Oh no”) 200, 201 -> parse(response.body()) in 400..499 -> throw HTTPException("Invalid request") in 500..599 -> throw HTTPException("Server error") else -> throw HTTPException("Error! Code {response.code()}”) }

Kotlin

Page 62: Practical tips for building apps with kotlin

Convert .java Automatic migration might not always result

the best code//Java private static final String MY_EXTRA=

"extra_sauce";

//Kotlin class SomeClass : AppCompatActivity() { companion object {

} //Other stuff here }

private val MY_EXTRA = “extra_sauce”

Page 63: Practical tips for building apps with kotlin

KotlinDo this instead

//Kotlin class SomeClass : AppCompatActivity() { //Other stuff here }

private val MY_EXTRA = “extra_sauce”

Page 64: Practical tips for building apps with kotlin

KotlinDo this instead

//Kotlin class SomeClass : AppCompatActivity() { //Other stuff here }

private const val MY_EXTRA = “extra_sauce”

Page 65: Practical tips for building apps with kotlin

Kotlin

class SomeClass : AppCompatActivity() { var someString = “” var someValue : Payment = /*..*/

override fun onCreate(b: Bundle?) { super.onCreate(b) if (someValue != null) someString = someValue!!.getCost() }

}

Page 66: Practical tips for building apps with kotlin

Kotlin

class SomeClass : AppCompatActivity() { var someString = “”

var someValue : Payment

override fun onCreate(b: Bundle?) { super.onCreate(b) if (someValue != null) someString = someValue!!.getCost() }

}

Page 67: Practical tips for building apps with kotlin

Kotlin

class SomeClass : AppCompatActivity() { var someString = “”

var someValue : Payment

override fun onCreate(b: Bundle?) { super.onCreate(b) someValue?.let{

someValue!!.getCost() } }

}

Page 68: Practical tips for building apps with kotlin

run

val password: Password = PasswordGenerator().run { seed = "someString" hash = {s -> someHash(s)} hashRepetitions = 1000

generate() }

Page 69: Practical tips for building apps with kotlin

val generator = PasswordGenerator().apply { seed = "someString" hash = {s -> someHash(s)} hashRepetitions = 1000 } val pasword = generator.generate()

apply

Page 70: Practical tips for building apps with kotlin

class MyFragment : Fragment(){ companion object { @JvmStatic fun newInstance(b:Boolean): MyFragment { val fragment = MyFragment() val args = Bundle() args.putBoolean("isValid",b) fragment.arguments = args return fragment }

Fragments

Page 71: Practical tips for building apps with kotlin

Kotlin

fun handleView() { for (item in list) if (item is TextView) item.text = getString(R.string.play) else doRandomOperationOn(item) }

Page 72: Practical tips for building apps with kotlin

Kotlin

fun handleView() { list.forEach { item -> when (item) { is TextView -> item.text = getString(R.string.play) else -> doRandomOperationOn(item) } }

}

Page 73: Practical tips for building apps with kotlin

class MyRecyclerAdapter(

val items: List,

val listener: (Item) -> Unit

){

….

}

Kotlin

recycler.adapter = MyRecyclerAdapter(items) { navigateToDetail(it) }

Page 74: Practical tips for building apps with kotlin

fun View.fadeOut(duration: Long = 500): ViewPropertyAnimator { return animate() .alpha(0.0f) .setDuration(duration) }

Optional params

icon.fadeOut() // fade out with default time (500) icon.fadeOut(1000) // fade out with custom time

Page 75: Practical tips for building apps with kotlin

Kotlin

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

//Then preferences.edit { putString("foo", "bar") putString("fizz", "buzz") remove("username") }

Page 76: Practical tips for building apps with kotlin

CODE

❤ KotlinJava to Kotlin

http://bit.ly/2glBYh8

http://bit.ly/KotlinIsAwesome

Koans - http://bit.ly/KotlinKoans

Page 77: Practical tips for building apps with kotlin

Thank you

https://medium.com/@aditlal

@aditlalhttp://bit.ly/devfestKotlin