16. val today = Date(2019, 6, 22)
if(today.isSaturday()) {
println("Today is a Saturday")
} else {
println("Today is not a Saturday")
}
fun Date.isSaturday(): Boolean {
return day == 6
}
17. Higher-Order Functions
fun <T> Iterable<T>.forEach(action: (T) -> Unit): Unit {
for (element in this){
action(element)
}
}
30. Challenge 1: Execute on a non-UI thread
Challenge 2: Get informed when the task is done
31. Challenge 1: Execute on a non-UI thread
Challenge 2: Get informed when the task is done
Android solutions
● AsyncTask
● Loaders (deprecated in Android P)
● RxJava
● Thread / HandlerThread / Executor with callbacks
32. Threads and callbacks
fun login(name, pass) {
val thread = Thread(Runnable() -> {
requestLogin(name, pass) { result ->
show(result)
}
}
thread.start()
}
33. Threads and callbacks
fun login(name, pass) {
val thread = Thread(Runnable() -> {
requestLogin(name, pass) { result ->
Handler(Looper.getMainLooper()) {
show(result)
}
}
43. fun login(name, pass) = launch(Dispatchers.IO){
val result = requestLogin(name, pass)
withContext(Dispatchers.Main) {
show(result)
}
}
Coroutine
● Not bound to a specific thread
● Complete with a result
44. fun login(name, pass) {
requestLogin(name, pass) { result -> show(result) }
}
Thread
49. Dispatchers.Default
● Common pool of shared background threads
● Use it for: computing-intensive coroutines
Dispatchers.Main
● Main thread
● Use it for: UI operations
50. Dispatchers.Default
● Common pool of shared background threads
● Use it for: computing-intensive coroutines
Dispatchers.IO
● Shared pool of on-demand created threads
● Use it for: IO-intensive blocking operations
Dispatchers.Main
● Main thread
● Use it for: UI operations
51. Dispatchers.Default
● Common pool of shared background threads
● Use it for: computing-intensive coroutines
Dispatchers.Unconfined
● Doesn’t confine the coroutine to any specific thread
● Don’t use it in code
Dispatchers.IO
● Shared pool of on-demand created threads
● Use it for: IO-intensive blocking operations
Dispatchers.Main
● Main thread
● Use it for: UI operations
70. Thank You!
Slack Community of 150+ Pakistani Android Developers from all over the world
http://bit.ly/androiddevs-pakistan
TheMaxCoderr
facebook.com/TheMaxCoder
Editor's Notes
Kotlin is a general-purpose language that supports both functional programming and object-oriented programming paradigms.
It’s an open-source project developed mainly by JetBrains with the help of the community.
Like Java, Kotlin is a statically typed language, however, in Kotlin you can omit the types, and it often looks as concise as some other dynamically-typed languages.
Kotlin is safe in a sense that Kotlin compiler helps to prevent a lot of possible types of errors.
Kotlin has really good interoperability with Java, and rich tooling support.
The project started at 2010. In 2017 it was acknowledged by Google as a first-class citizen on Android.
Kotlin usage and Kotlin community is growing very fast.
One can compile Kotlin code for different platforms, including JVM, Android, JavaScript and Native.
Kotlin compiles to JVM bytecode starting from 1.6, so you can use it even for older versions of JVM without upgrading it.
Thanks to Kotlin and Java interop, you can easily mix Kotlin and Java sources. You don’t have to convert all the existing code into Kotlin, you can slowly add new functionality written in Kotlin into existing Java project.
IntelliJ IDEA and Android studio automatically convert Java code into Kotlin code with the copy-paste. That might be used for learning purposes or to provide smooth migration.
Kotlin is an official language for Android, and a lot of Android specific documentation now targets Kotlin.
Check out the Android KTX project which contains lots of helpful extensions for Kotlin.
With Kotlin you can target JavaScript too. The compiler generates readable JS code from your Kotlin code. Note that converting Kotlin code to JavaScript code is called “transpiling”, not “compiling”.
You can use the dynamic type to access any JS library without strong typing. To access third-party frameworks with a strongly-typed API, you can convert TypeScript definitions from the ”Definitely Typed” type definitions repository to Kotlin using the ts2kt tool.
There are platforms, where virtual machine is not needed, banned or too heavy. Kotlin/Native is a good choice to jump into the world of native code. It uses LLVM backend and targets many native platforms. In addition to it, it adds an interop level with C and Objective-C libraries.
You can use it to compile parts of your app for iOS.
You can share the code written for different platforms by using Kotlin Multiplatform.
Now we will talk about some of Kotlin’s coolest features, I have tried to keep them beginner friendly.
Kotlin functions are first-class, which means that they can be stored in variables and data structures, passed as arguments to and returned from other higher-order functions.
Collection types, such as Iterable, Collection, List, Set, Map
This is lambda expression that is saved in the argument
Stld contains tons of such funtions
Kotlin functions are first-class, which means that they can be stored in variables and data structures, passed as arguments to and returned from other higher-order functions.
As Android developers, we have all sorts of long running tasks we need to execute: from network requests, to database operations or processing an image.
But, in general, doing long running tasks comes with several challenges
First, we want to make sure that all of these tasks are executed on a non-UI thread.
We know that we have 16ms to draw the UI and anything taking more than those 16ms, will lead to jank
So some of the APIs we use, force us to long running tasks on a background thread: the network stack throws NetworkOnMainThreadException Room throws java.lang.IllegalStateException: Cannot access database on the main thread
So executing long running operations on a non-UI thread is a must in Android
Next challenge is knowing when such a task is done. Completing a long running task often leads to some consequences - we’re saving the network response to the database, we’re informing the user of the success or failure of the operation. So, no matter what happens, we want to work with the result of the task.
In Android we can approach these challenges with several APIs:
We can use an AsyncTask, but then, you have to make sure you’re not connecting it to the lifecycle of an Activity and create memory leaks on Activity rotation and that you cancel the task when needed.
We can use Loaders, but then this API was deprecated in Android P in favor of LiveData and ViewModels. But even with LiveData, we still need a way to run tasks on a background thread.
You can use RxJava but keep in mind that RxJava brings with it a powerful streams API and you shouldn’t be using it just to switch threads.
So, we could just handle our threading by directly using APIs like Thread, HandlerThread or Executor but the problem is that all of these APIs would need to be used with callbacks. The role of the callback would be to provide an action to be taken once the task is performed
When working with callbacks it’s easy to get in a callback hell, decreasing the readability of the code.
And, guess what, that show needs to be on the UI so we need to get a reference to the main looper
If we’re not creating a new thread for our login request, the code looks something like this:
But if we’re running this on the UI thread but We’re blocking the thread
Only after the login is returned, we can unblock our thread and draw the UI again
What we want is to let the thread do other things while waiting for the completion of a task, so more precisely, we want to suspend the thread at certain points.
To achieve this, we will be working with coroutines.
That’s what a coroutine is - an instance of a suspendable computation.
Function A has to be completed before Function B continue. The thread is locked for Function A to complete it’s execution.
Function A, while has started, could be suspended, and let Function B execute, then only resume later. The thread is not locked by Function A.
Coroutines allow us to write async code sequentially
Often, they tend to be compared to lightweight threads because just like with threads, it takes a block of code to run, it’s created and it’s started.
But the difference appears in the fact that they’re not bound to a specific thread, it’s easy to switch threads and they complete with a result
The points in the code where we want to suspend the execution, are called suspension points
We define them using the suspend modifier.
But, the suspend modifier by itself doesn’t do anything. It doesn’t make the function asynchronous.
This should be called only from a coroutine or another suspend function
They signify that that function will not block the caller thead.
In order to enforce the convention, we have to use the withContext function.
This function calls the specified suspending block with a given coroutine context, suspends until it completes, and returns the result.
The withContext gets as a parameter a Dispatcher. The role of the dispatcher is to move the work to a different thread pool
So in our login case, when we’re calling withContent(Dispatchers.IO), it means that we’re shifting the execution of the code block to a new thread.
Suspension functions can only be called from other suspension functions or from coroutines.
Coroutines allows us to write the code sequentially, without the need of callbacks.
The code is now sequential.
We can depend on data, for example here, we can depend on the auth token coming from authenticate and pass it to requestLogin
Try and catch works as expected
Let’s say that when the login button was pressed, we want to launch a coroutine to request the login, and then, once we got the response, we want to show the login status
To launch a coroutine, we need to create a job and a coroutine scope, based on a dispatcher and the job.
Then, based on the scope, we create a new coroutine by calling launch. Inside the coroutine block, we request the login
The scope allows us to track all of the coroutines we’re creating
Launch also allows us to set the dispatcher on which the coroutine is launched
But, because we launched something, it also means we need to make sure we cancel the coroutines created at a certain point. For this we would use the cancel method from Job.
What if the Activity gets destroyed before we got the response?
We need to make sure that we’re cancelling the coroutine and not leaking any memory.
So, this means that the lifecycle of a coroutine needs to be related to the lifecyle of another object - in Android the best place to launch coroutines is in VIewModels
Then in onCleared we can cancel the job
So, overall, this is how our viewmodel would look like.
But, because this is a lot of boilerplate
We have a new handy library: lifecycle-viewmodel-ktx
The library adds a viewModelScope as an extension function of the ViewModel class. This scope is bound to Dispatchers.Main and will automatically be cancelled when the ViewModel is cleared. Instead of having to create a new scope in every ViewModel, you can just use viewModelScope and the library will take care of setting up and clearing the scope for you.