save time with kotlin in android development

77
Save Time in Android Development with Kotlin Adit Lal | @aditlal

Upload: adit-lal

Post on 21-Jan-2018

256 views

Category:

Software


1 download

TRANSCRIPT

Save Time in Android Development with Kotlin

Adit Lal | @aditlal

Agenda

What is Kotlin?

Perfect for Android

Migration guide

Best Practices

Summary - QnA

100 % interoperable with Java

Developed by JetBrains

Background

What is Kotlin?

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

OOP language

with functional aspects

Modern and powerful language

Safe concise & readable

code

First class tool support

What is Kotlin?

Kotlin

• Null safety• Conciseness• Lambdas• Higher order functions• Mutability protection• Static typing + Smart Casts

We will cover :

Kotlin

Kotlin works on same byte code

Kotlin - Syntax

• Types follow variable/function names • Functions start with fun keyword• Default constructor in class signature • Semicolons not required

Kotlin - Syntax

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

Access modifier

KeywordFunction name

Param name Param type

Return type

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

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

Kotlin - Syntax

//java String sName = person.getSecretName()

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

Kotlin - Null Safety

NULLS ARE PART OF THE TYPE SYSTEM

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.lengthvar l = b.length

// compilation error

// OK

// error: variable 'b' can be null

Kotlin - Null Safety

Helpers

Safe accessor  ?

Elvis operator  ?:

val toDisplay: String = serverResponse

Kotlin - Null

// if response is null, we'll display a default messageval toDisplay: String = response ?: defaultMessage

Kotlin - Null

// cascading null safetyval maybeName: String? = maybeNullValue?.someProperty?.name

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

Kotlin - Null

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

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

Casting

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

} else { // handle else }

Kotlin - Smart casting

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

Class

// Wont Compileclass Student : Person()

class Person

open class Person

Class

//It works nowclass Student : Person()

Higher order functions

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

output

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

Kotlin - Features

… and More

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

Kotlin - Features

… and Even More

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

Perfect for

• Versatile language

• Complete interop with Java

• Compact runtime

• Enhance development speed with less

code

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

Common Concerns

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

Common Concerns

•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

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

•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

Java>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

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

• 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

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

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 } }

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 } }

view.setOnClickListener{ toast(“Hello") }

Concise

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

view.setOnClickListener{ view -> doSomethingWithView() }

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)//this is called from fragment

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

Kotlin -

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

Data classes

Kotlin - Data classes

equals() & hashCode()

toString()

copy() function

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

KotlinWhen expression

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

... }

Android

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

... }

Android

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

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

ImageLoadingExtensions.kt

Android

//ThenivAvatar.loadUrl("some_fancy_url")

Utils

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

//call view.visible()

Utils

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

//call tvTotalPrice.setHeight(50)

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

} } return this

}

Utils

//call showOnUiThread(updateUIWithNewData())

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

Adopting kotlin into android code

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

When to use lateinit

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

lateinit Modifier

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

Lazy Initialisation

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

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

Kotlin

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

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

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 {

} … }

private val MY_EXTRA = “extra_sauce”

KotlinDo this instead

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

private val MY_EXTRA = “extra_sauce”

KotlinDo this instead

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

private const val MY_EXTRA = “extra_sauce”

Kotlin

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

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

}

Kotlin

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

var someValue : Payment

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

}

Kotlin

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

var someValue : Payment

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

someValue!!.getCost() } }

}

run

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

generate() }

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

apply

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

Kotlin

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

Kotlin

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

}

class MyRecyclerAdapter(val items: List, val listener: (Item) -> Unit){….}

Kotlin

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

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

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") }

CODE

❤ KotlinJava to Kotlin

http://bit.ly/2glBYh8

http://bit.ly/KotlinIsAwesome

Koans - http://bit.ly/KotlinKoans

Thank you

https://medium.com/@aditlal@aditlal