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 Keyword Function 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 Safety Types 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
Kotlin - Null Safety Helpers Safe accessor  ? Elvis operator  ?:
val toDisplay: String = serverResponse Kotlin - Null // if response is null, we'll display a default message val toDisplay: String = response ?: defaultMessage
Kotlin - Null // cascading null safety val 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 extensions apply 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" } } Kotlin When 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 //Then ivAvatar.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 mutable If 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") //improved val 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”
Kotlin Do this instead //Kotlin class SomeClass : AppCompatActivity() { //Other stuff here } private val MY_EXTRA = “extra_sauce”
Kotlin Do 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 ❤ Kotlin Java to Kotlin http://bit.ly/2glBYh8 http://bit.ly/KotlinIsAwesome Koans - http://bit.ly/KotlinKoans
Thank you https://medium.com/@aditlal @aditlal

Save time with kotlin in android development

  • 1.
    Save Time inAndroid Development with Kotlin Adit Lal | @aditlal
  • 2.
    Agenda What is Kotlin? Perfectfor Android Migration guide Best Practices Summary - QnA
  • 3.
    100 % interoperable withJava Developed by JetBrains Background
  • 4.
    What is Kotlin? Staticallytyped programming language for the JVM, Android and the browser
  • 6.
  • 7.
    Kotlin • Null safety •Conciseness • Lambdas • Higher order functions • Mutability protection • Static typing + Smart Casts We will cover :
  • 8.
    Kotlin Kotlin works onsame byte code
  • 9.
    Kotlin - Syntax •Types follow variable/function names • Functions start with fun keyword • Default constructor in class signature • Semicolons not required
  • 10.
    Kotlin - Syntax privatefun sum(first: Int , second: Int): Int { return first + second } Access modifier Keyword Function name Param name Param type Return type
  • 11.
    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
  • 12.
    Kotlin - Syntax valname: String ="John" // final var name: String ="John" //Mutable ex: name= "Johnny" Two types of variables val name ="John" // Types are auto-inferred
  • 13.
    Kotlin - Syntax //java StringsName = person.getSecretName() //kotlin person.secretName = “Batman” var fName = person.secretName
  • 14.
    Kotlin - NullSafety NULLS ARE PART OF THE TYPE SYSTEM
  • 15.
    Kotlin - NullSafety Types 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
  • 16.
    Kotlin - NullSafety Helpers Safe accessor  ? Elvis operator  ?:
  • 17.
    val toDisplay: String= serverResponse Kotlin - Null // if response is null, we'll display a default message val toDisplay: String = response ?: defaultMessage
  • 18.
    Kotlin - Null //cascading null safety val maybeName: String? = maybeNullValue?.someProperty?.name val maybeNullValue: MyValue? = /*..*/
  • 19.
    Kotlin - Null //safe operation maybeNullValue?.let { //executed if not null } val maybeNullValue: MyValue? = /*..*/
  • 20.
    Casting if (obj instanceOfMyType) { value = ((MyType)obj).getXValue(); } else { // handle else }
  • 21.
    Kotlin - Smartcasting if (obj is MyType) { value = obj.x } else { // handle else }
  • 22.
    Class // Wont CompileclassStudent : Person() class Person
  • 23.
    open class Person Class //Itworks nowclass Student : Person()
  • 24.
    Higher order functions Functionsthat can take functions as arguments and also return function as the output
  • 25.
    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
  • 26.
    Kotlin - Features …and More • Visibility Modifiers • Companion Objects • Nested, Sealed Classes • Generics • Coroutines • Operator overloading • Exceptions • Annotations • Reflection • and more
  • 27.
    Kotlin - Features …and Even More • Infix extension methods • Interfaces • Interface Delegation • Property Delegation • Destructuring • Safe Singletons • Init blocks • Enums • Multiline Strings • Tail recursion
  • 28.
    Perfect for • Versatilelanguage • Complete interop with Java • Compact runtime • Enhance development speed with less code
  • 29.
    “But I’m comfortableand experienced with Java.” Common Concerns
  • 30.
    “I don’t wantto convert my entire codebase to a new language.” Common Concerns
  • 31.
    •Compiled to bytecode (like Java) •No impact on performance •Some Kotlin code faster •Lambdas that can be inlined •Built-in operations faster than DIY implementations Kotlin
  • 32.
    How to migrate Startin 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
  • 33.
    •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
  • 34.
  • 35.
    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
  • 36.
    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
  • 37.
    • View binding(like Butter Knife) • No instance variables required • How? Android extensions apply 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
  • 38.
    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
  • 39.
    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 } }
  • 40.
    Android extensions import kotlinx.android.synthetic.activity_main.* classHomeActivity : AppCompatActivity() { override fun onCreate(b: Bundle?) { super.onCreate(b) setContentView(R.layout.activity_main) view.alpha = 1f } }
  • 41.
    view.setOnClickListener{ toast(“Hello") } Concise view.setOnClickListener(object: View.OnClickListener { override fun onClick(v: View?) { toast("Hello") } }) view.setOnClickListener{ view -> doSomethingWithView() }
  • 42.
    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
  • 43.
    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
  • 44.
    Kotlin - data classPerson( val name: String, var surname: String = "", val id: String ) Data classes
  • 45.
    Kotlin - Dataclasses equals() & hashCode() toString() copy() function
  • 46.
    fun evaluateObject(obj: Any):String { return when(obj){ is String -> "Ahoy !!" is Int -> "Lucky no is $obj" else -> "Object is in space" } } Kotlin When expression
  • 47.
  • 48.
    // Kotlin if (name.contains(str,true)) { ... } Android
  • 49.
    for (i in1..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
  • 50.
    fun ImageView.loadUrl(url: String){ Glide.with(context).load(url).into(this) } ImageLoadingExtensions.kt Android //Then ivAvatar.loadUrl("some_fancy_url")
  • 51.
    Utils fun View.visible() { visibility= View.VISIBLE } fun View.gone() { visibility = View.GONE } //call view.visible()
  • 52.
    Utils fun View.setHeight(height: Int){ val params = layoutParams params.height = height layoutParams = params } //call tvTotalPrice.setHeight(50)
  • 53.
    fun Activity.showOnUiThread(init: Activity.()-> Unit) : Activity { if (!isFinishing) { runOnUiThread { init() } } return this } Utils //call showOnUiThread(updateUIWithNewData())
  • 54.
    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
  • 55.
  • 56.
    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
  • 57.
    When to use lateinit Ifyou’re variable is mutable If you’re sending a object from another component/ screen — ex Intent extras lateinit Modifier
  • 58.
    val myUtil bylazy { SomeUtil(parameter1, parameter2) } Lazy Initialisation
  • 59.
    val hashMap =HashMap<String, String>() hashMap.put("keyA", "valueA") hashMap.put("keyB", "valueB") hashMap.put("keyC", "valueC") //improved val map = mapOf( "keyA" to "valueA", "keyB" to "valueB", "keyC" to "valueC" ) Kotlin
  • 60.
    fun listItemsToDisplay(): List<ListItem>{ return listOf(users) + friends() + recentSearches() } Kotlin
  • 61.
    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
  • 62.
    Convert .java Automatic migrationmight 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”
  • 63.
    Kotlin Do this instead //Kotlin classSomeClass : AppCompatActivity() { //Other stuff here } private val MY_EXTRA = “extra_sauce”
  • 64.
    Kotlin Do this instead //Kotlin classSomeClass : AppCompatActivity() { //Other stuff here } private const val MY_EXTRA = “extra_sauce”
  • 65.
    Kotlin class SomeClass :AppCompatActivity() { var someString = “” var someValue : Payment = /*..*/ override fun onCreate(b: Bundle?) { super.onCreate(b) if (someValue != null) someString = someValue!!.getCost() } }
  • 66.
    Kotlin class SomeClass :AppCompatActivity() { var someString = “” var someValue : Payment override fun onCreate(b: Bundle?) { super.onCreate(b) if (someValue != null) someString = someValue!!.getCost() } }
  • 67.
    Kotlin class SomeClass :AppCompatActivity() { var someString = “” var someValue : Payment override fun onCreate(b: Bundle?) { super.onCreate(b) someValue?.let{ someValue!!.getCost() } } }
  • 68.
    run val password: Password= PasswordGenerator().run { seed = "someString" hash = {s -> someHash(s)} hashRepetitions = 1000 generate() }
  • 69.
    val generator =PasswordGenerator().apply { seed = "someString" hash = {s -> someHash(s)} hashRepetitions = 1000 } val pasword = generator.generate() apply
  • 70.
    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
  • 71.
    Kotlin fun handleView() { for(item in list) if (item is TextView) item.text = getString(R.string.play) else doRandomOperationOn(item) }
  • 72.
    Kotlin fun handleView() { list.forEach{ item -> when (item) { is TextView -> item.text = getString(R.string.play) else -> doRandomOperationOn(item) } } }
  • 73.
    class MyRecyclerAdapter( val items:List, val listener: (Item) -> Unit ){ …. } Kotlin recycler.adapter = MyRecyclerAdapter(items) { navigateToDetail(it) }
  • 74.
    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
  • 75.
    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") }
  • 76.
    CODE ❤ Kotlin Java toKotlin http://bit.ly/2glBYh8 http://bit.ly/KotlinIsAwesome Koans - http://bit.ly/KotlinKoans
  • 77.