Save time with kotlin in android development
Transcript of Save time with kotlin in android development
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 - 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 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
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? = /*..*/
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
•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
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
fun evaluateObject(obj: Any): String { return when(obj){ is String -> "Ahoy !!" is Int -> "Lucky no is $obj" else -> "Object is in space" } }
KotlinWhen expression
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
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 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