Like light-weight threads.
fun main() = runBlocking {
repeat(100_000) { // launch a lot of coroutines
thread {
delay(1000L)
print(".")
}
}
}
fun main() = runBlocking {
repeat(100_000) { // launch a lot of coroutines
launch {
delay(1000L)
print(".")
}
}
}
fun postItem(item: Item) {
requestTokenAsync { token ->
createPostAsync(token, item) { post ->
processPost(post)
}
}
}
Rx/Futures/Promises to the rescue
Basic Sample with Android
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
GlobalScope.launch (Dispatchers.Main){
toast("Hello world!!!")
delay(10, TimeUnit.SECONDS)
textView.text = "Hello!! Android Taipei!!"
}
}
}
GlobalScope.launch
Samples with Retrofit
interface RetrofitService {
@GET("/posts")
fun getPosts(): Call<List<Post>>
}
Declaring an Interface (Call)
interface RetrofitService {
@GET("/posts")
fun getPosts(): Deferred<<List<Post>>
}
Declaring an Interface (Coroutine)
object RetrofitFactory {
const val BASE_URL = "https://sample.com"
fun makeRetrofitService(): RetrofitService {
return Retrofit.Builder()
.baseUrl(BASE_URL)
.addCallAdapterFactory(CoroutineCallAdapterFactory())
.build().create(RetrofitService::class.java)
}
}
Building Retrofit Service
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val service = RetrofitFactory.makeRetrofitService()
GlobalScope.launch(Dispatchers.Main) {
val request = service.getPosts()
try {
val response = request.await()
// Do something with the response.
} catch (e: HttpException) {
toast(e.code())
} catch (e: Throwable) {
toast("Ooops: Something else went wrong")
}
}
}
Bringing it all together
fun main() {
GlobalScope.launch {
delay(1000L)
println("World!")
}
println("Hello,")
Thread.sleep(2000L)
}
public interface CoroutineScope {
/**
* Context of this scope.
*/
public val coroutineContext: CoroutineContext
}
public object GlobalScope : CoroutineScope {
/**
* Returns [EmptyCoroutineContext].
*/
override val coroutineContext: CoroutineContext
get() = EmptyCoroutineContext
}
public fun CoroutineScope.launch(
context: CoroutineContext = EmptyCoroutineContext,
start: CoroutineStart = CoroutineStart.DEFAULT,
block: suspend CoroutineScope.() -> Unit
): Job {
....
}
suspend fun delay(timeMillis: Long): Unit (source)
Delays coroutine for a given time without blocking a thread and
resumes it after a specified time. This suspending function is
cancellable.
Declare functions with their parameters and
return values.
• (Int) -> String
• () -> String
• (Int, Int) -> String
• () -> () -> String
var print: (Int) -> String
• var printHello: () -> String
• Var printNumbers: (Int, Int) -> String
suspend () -> Unit
public fun CoroutineScope.launch(
context: CoroutineContext = EmptyCoroutineContext,
start: CoroutineStart = CoroutineStart.DEFAULT,
block: suspend CoroutineScope.() -> Unit
): Job {
....
}
Suspending functions can be used inside coroutines just like regular
functions, but their additional feature is that they can, in turn, use other
suspending functions.
Does something long & waits for it to complete without blocking.
fun main() = runBlocking<Unit> {
GlobalScope.launch {
delay(1000L)
println("World!")
}
println("Hello,")
delay(2000L)
}
fun main() = runBlocking {
val job = GlobalScope.launch {
delay(1000L)
println("World!")
}
println("Hello,")
job.join()
}
Structured concurrency
fun main() = runBlocking {
launch {
delay(1000L)
println("World!")
}
println("Hello,")
}
fun main() = runBlocking {
launch {
printWorld()
}
println("Hello,")
}
private suspend fun printWorld() {
delay(1000L)
println("World!")
}
• JVM Options: -Dkotlinx.coroutines.debug
• Get thread name: Thread.currentThread().name
fun main() = runBlocking<Unit> {
val a = async {
log("I'm computing a piece of the answer")
6
}
val b = async {
log("I'm computing another piece of the answer")
7
}
log("The answer is ${a.await() * b.await()}")
}
[main @coroutine#2] I'm computing a piece of the answer
[main @coroutine#3] I'm computing another piece of the answer
[main @coroutine#1] The answer is 42
•
•
•
•
•
•
Sequential by default
fun main() = runBlocking<Unit> {
val time = measureTimeMillis {
val one = doSomethingUsefulOne()
val two = doSomethingUsefulTwo()
println("The answer is ${one + two}")
}
println("Completed in $time ms")
}
suspend fun doSomethingUsefulOne(): Int {
delay(1000L) // pretend we are doing something useful here
return 13
}
suspend fun doSomethingUsefulTwo(): Int {
delay(1000L) // pretend we are doing something useful here, too
return 29
}
Sequential by default
The answer is 42
Completed in 2010 ms
•
•
public fun <T> CoroutineScope.async(
context: CoroutineContext = EmptyCoroutineContext,
start: CoroutineStart = CoroutineStart.DEFAULT,
block: suspend CoroutineScope.() -> T
): Deferred<T> {
....
}
public fun CoroutineScope.launch(
context: CoroutineContext =
EmptyCoroutineContext,
start: CoroutineStart = CoroutineStart.DEFAULT,
block: suspend CoroutineScope.() -> Unit
): Job {
....
}
Concurrent using async
fun main() = runBlocking<Unit> {
val time = measureTimeMillis {
val one = async { doSomethingUsefulOne() }
val two = async { doSomethingUsefulTwo() }
println("The answer is ${one.await() + two.await()}")
}
println("Completed in $time ms")
}
suspend fun doSomethingUsefulOne(): Int {
delay(1000L) // pretend we are doing something useful here
return 13
}
suspend fun doSomethingUsefulTwo(): Int {
delay(1000L) // pretend we are doing something useful here
return 29
}
public fun CoroutineScope.launch(
context: CoroutineContext = EmptyCoroutineContext,
start: CoroutineStart = CoroutineStart.DEFAULT,
block: suspend CoroutineScope.() -> Unit
): Job {
....
}
•
•
•
•
fun main() = runBlocking<Unit> {
launch {
println("main runBlocking : I'm working in thread ${Thread.currentThread().name}")
}
launch(Dispatchers.Unconfined) {
println("Unconfined : I'm working in thread ${Thread.currentThread().name}")
}
launch(Dispatchers.Default) { // will get dispatched to DefaultDispatcher
println("Default : I'm working in thread ${Thread.currentThread().name}")
}
launch(newSingleThreadContext("MyOwnThread")) { // will get its own new thread
println("newSingleThreadContext: I'm working in thread ${Thread.currentThread().name}")
}
}
Unconfined : I'm working in thread main @coroutine#3
Default : I'm working in thread DefaultDispatcher-worker-1 @coroutine#4
newSingleThreadContext: I'm working in thread MyOwnThread @coroutine#5
main runBlocking : I'm working in thread main @coroutine#2
•
•
•
•
•
•
•
Kotlin - Coroutine
Kotlin - Coroutine
Kotlin - Coroutine
Kotlin - Coroutine

Kotlin - Coroutine

  • 4.
  • 5.
    fun main() =runBlocking { repeat(100_000) { // launch a lot of coroutines thread { delay(1000L) print(".") } } }
  • 6.
    fun main() =runBlocking { repeat(100_000) { // launch a lot of coroutines launch { delay(1000L) print(".") } } }
  • 7.
    fun postItem(item: Item){ requestTokenAsync { token -> createPostAsync(token, item) { post -> processPost(post) } } }
  • 8.
  • 9.
  • 10.
    class MainActivity :AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) GlobalScope.launch (Dispatchers.Main){ toast("Hello world!!!") delay(10, TimeUnit.SECONDS) textView.text = "Hello!! Android Taipei!!" } } } GlobalScope.launch
  • 11.
  • 12.
    interface RetrofitService { @GET("/posts") fungetPosts(): Call<List<Post>> } Declaring an Interface (Call)
  • 13.
    interface RetrofitService { @GET("/posts") fungetPosts(): Deferred<<List<Post>> } Declaring an Interface (Coroutine)
  • 14.
    object RetrofitFactory { constval BASE_URL = "https://sample.com" fun makeRetrofitService(): RetrofitService { return Retrofit.Builder() .baseUrl(BASE_URL) .addCallAdapterFactory(CoroutineCallAdapterFactory()) .build().create(RetrofitService::class.java) } } Building Retrofit Service
  • 15.
    class MainActivity :AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val service = RetrofitFactory.makeRetrofitService() GlobalScope.launch(Dispatchers.Main) { val request = service.getPosts() try { val response = request.await() // Do something with the response. } catch (e: HttpException) { toast(e.code()) } catch (e: Throwable) { toast("Ooops: Something else went wrong") } } } Bringing it all together
  • 18.
    fun main() { GlobalScope.launch{ delay(1000L) println("World!") } println("Hello,") Thread.sleep(2000L) }
  • 20.
    public interface CoroutineScope{ /** * Context of this scope. */ public val coroutineContext: CoroutineContext }
  • 21.
    public object GlobalScope: CoroutineScope { /** * Returns [EmptyCoroutineContext]. */ override val coroutineContext: CoroutineContext get() = EmptyCoroutineContext }
  • 22.
    public fun CoroutineScope.launch( context:CoroutineContext = EmptyCoroutineContext, start: CoroutineStart = CoroutineStart.DEFAULT, block: suspend CoroutineScope.() -> Unit ): Job { .... }
  • 23.
    suspend fun delay(timeMillis:Long): Unit (source) Delays coroutine for a given time without blocking a thread and resumes it after a specified time. This suspending function is cancellable.
  • 25.
    Declare functions withtheir parameters and return values. • (Int) -> String • () -> String • (Int, Int) -> String • () -> () -> String
  • 26.
    var print: (Int)-> String • var printHello: () -> String • Var printNumbers: (Int, Int) -> String
  • 27.
  • 28.
    public fun CoroutineScope.launch( context:CoroutineContext = EmptyCoroutineContext, start: CoroutineStart = CoroutineStart.DEFAULT, block: suspend CoroutineScope.() -> Unit ): Job { .... }
  • 29.
    Suspending functions canbe used inside coroutines just like regular functions, but their additional feature is that they can, in turn, use other suspending functions.
  • 30.
    Does something long& waits for it to complete without blocking.
  • 31.
    fun main() =runBlocking<Unit> { GlobalScope.launch { delay(1000L) println("World!") } println("Hello,") delay(2000L) }
  • 32.
    fun main() =runBlocking { val job = GlobalScope.launch { delay(1000L) println("World!") } println("Hello,") job.join() }
  • 33.
    Structured concurrency fun main()= runBlocking { launch { delay(1000L) println("World!") } println("Hello,") }
  • 35.
    fun main() =runBlocking { launch { printWorld() } println("Hello,") } private suspend fun printWorld() { delay(1000L) println("World!") }
  • 37.
    • JVM Options:-Dkotlinx.coroutines.debug • Get thread name: Thread.currentThread().name
  • 38.
    fun main() =runBlocking<Unit> { val a = async { log("I'm computing a piece of the answer") 6 } val b = async { log("I'm computing another piece of the answer") 7 } log("The answer is ${a.await() * b.await()}") }
  • 39.
    [main @coroutine#2] I'mcomputing a piece of the answer [main @coroutine#3] I'm computing another piece of the answer [main @coroutine#1] The answer is 42
  • 41.
  • 43.
    Sequential by default funmain() = runBlocking<Unit> { val time = measureTimeMillis { val one = doSomethingUsefulOne() val two = doSomethingUsefulTwo() println("The answer is ${one + two}") } println("Completed in $time ms") } suspend fun doSomethingUsefulOne(): Int { delay(1000L) // pretend we are doing something useful here return 13 } suspend fun doSomethingUsefulTwo(): Int { delay(1000L) // pretend we are doing something useful here, too return 29 }
  • 44.
    Sequential by default Theanswer is 42 Completed in 2010 ms
  • 45.
  • 46.
    public fun <T>CoroutineScope.async( context: CoroutineContext = EmptyCoroutineContext, start: CoroutineStart = CoroutineStart.DEFAULT, block: suspend CoroutineScope.() -> T ): Deferred<T> { .... } public fun CoroutineScope.launch( context: CoroutineContext = EmptyCoroutineContext, start: CoroutineStart = CoroutineStart.DEFAULT, block: suspend CoroutineScope.() -> Unit ): Job { .... }
  • 47.
    Concurrent using async funmain() = runBlocking<Unit> { val time = measureTimeMillis { val one = async { doSomethingUsefulOne() } val two = async { doSomethingUsefulTwo() } println("The answer is ${one.await() + two.await()}") } println("Completed in $time ms") } suspend fun doSomethingUsefulOne(): Int { delay(1000L) // pretend we are doing something useful here return 13 } suspend fun doSomethingUsefulTwo(): Int { delay(1000L) // pretend we are doing something useful here return 29 }
  • 49.
    public fun CoroutineScope.launch( context:CoroutineContext = EmptyCoroutineContext, start: CoroutineStart = CoroutineStart.DEFAULT, block: suspend CoroutineScope.() -> Unit ): Job { .... }
  • 50.
  • 51.
    fun main() =runBlocking<Unit> { launch { println("main runBlocking : I'm working in thread ${Thread.currentThread().name}") } launch(Dispatchers.Unconfined) { println("Unconfined : I'm working in thread ${Thread.currentThread().name}") } launch(Dispatchers.Default) { // will get dispatched to DefaultDispatcher println("Default : I'm working in thread ${Thread.currentThread().name}") } launch(newSingleThreadContext("MyOwnThread")) { // will get its own new thread println("newSingleThreadContext: I'm working in thread ${Thread.currentThread().name}") } }
  • 52.
    Unconfined : I'mworking in thread main @coroutine#3 Default : I'm working in thread DefaultDispatcher-worker-1 @coroutine#4 newSingleThreadContext: I'm working in thread MyOwnThread @coroutine#5 main runBlocking : I'm working in thread main @coroutine#2
  • 53.
  • 54.