Last active
September 19, 2020 18:42
-
-
Save Audhil/8a1b4cf98056ecec8f21e1b5d8ae07c2 to your computer and use it in GitHub Desktop.
Kotlin CoRoutines in NutShell!
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.example.croutinesdemo | |
import retrofit2.Call | |
import retrofit2.Response | |
import retrofit2.http.GET | |
// api | |
interface API { | |
@GET("/comments") | |
fun getComments(): Call<List<Comment>> // apiCallWithRetrofitDemo1(), apiCallWithRetrofitDemo2() | |
// @GET("/comments") | |
// suspend fun getComments(): Response<List<Comment>> // apiCallWithRetrofitDemo1(), apiCallWithRetrofitDemo2() | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.example.croutinesdemo | |
import android.content.Intent | |
import androidx.appcompat.app.AppCompatActivity | |
import android.os.Bundle | |
import androidx.lifecycle.lifecycleScope | |
import kotlinx.android.synthetic.main.activity_main.* | |
import kotlinx.coroutines.* | |
import retrofit2.Retrofit | |
import retrofit2.await | |
import retrofit2.awaitResponse | |
import retrofit2.converter.gson.GsonConverterFactory | |
import kotlin.system.measureTimeMillis | |
class MainActivity : AppCompatActivity() { | |
override fun onCreate(savedInstanceState: Bundle?) { | |
super.onCreate(savedInstanceState) | |
setContentView(R.layout.activity_main) | |
println("yup hello from ${Thread.currentThread().name}") | |
// basicCoroutine1() | |
// suspendFunc2() | |
// contextSwitching3() | |
// runBlockingDemo4() | |
// jobJoinDemo5() | |
// jobCancelDemo5() | |
// jobCancel2Demo5() | |
// jobCancel3Demo5() | |
// jobCancel4Demo5() | |
// asyncAwait1Demo6() | |
// asyncAwait2Demo6() | |
// asyncAwait3Demo6() | |
// customScopes1Demo7() | |
// customScopes2Demo7() | |
// setUpRetroFit() | |
// apiCallWithRetrofitDemo1() | |
// apiCallWithRetrofitDemo2() | |
// apiCallWithRetrofitDemo3() | |
} | |
// private fun apiCallWithRetrofitDemo3() { | |
// GlobalScope.launch(Dispatchers.IO) { | |
// val response = apiService.getComments() | |
// if (response.isSuccessful) { | |
// response.body()?.forEach { | |
// println("yup: it is comment: $it") | |
// } | |
// } | |
// } | |
// } | |
private fun apiCallWithRetrofitDemo2() { | |
GlobalScope.launch(Dispatchers.IO) { | |
val response = apiService.getComments().awaitResponse() | |
if (response.isSuccessful) { | |
response.body()?.forEach { | |
println("yup: it is comment: $it") | |
} | |
} | |
} | |
} | |
private val BASE_URL = "https://jsonplaceholder.typicode.com" | |
private lateinit var apiService: API | |
private fun setUpRetroFit() { | |
apiService = Retrofit.Builder() | |
.baseUrl(BASE_URL) | |
.addConverterFactory(GsonConverterFactory.create()) | |
.build() | |
.create(API::class.java) | |
} | |
private fun apiCallWithRetrofitDemo1() { | |
GlobalScope.launch(Dispatchers.IO) { | |
val comments = apiService.getComments().await() | |
comments.forEach { | |
println("yup: it is comment: $it") | |
} | |
} | |
} | |
private fun customScopes2Demo7() { | |
// this is best practice - similarly | |
/* | |
* 2020-09-16 00:47:01.567 14972-14972/com.example.croutinesdemo I/System.out: yup hello from main | |
2020-09-16 00:47:04.703 14972-14972/com.example.croutinesdemo I/System.out: yup: still running! | |
2020-09-16 00:47:05.706 14972-14972/com.example.croutinesdemo I/System.out: yup: still running! | |
2020-09-16 00:47:06.708 14972-14972/com.example.croutinesdemo I/System.out: yup: still running! | |
2020-09-16 00:47:07.712 14972-14972/com.example.croutinesdemo I/System.out: yup: still running! | |
2020-09-16 00:47:08.726 14972-14972/com.example.croutinesdemo I/System.out: yup: still running! | |
*/ | |
tvDummy.setOnClickListener { | |
// bad practice | |
lifecycleScope.launch { | |
while (true) { | |
delay(1000L) | |
println("yup: still running!") | |
} | |
} | |
// launch another coroutine | |
GlobalScope.launch { | |
delay(5000L) | |
startActivity(Intent(this@MainActivity, SecondActivity::class.java)) | |
finish() | |
} | |
} | |
} | |
private fun customScopes1Demo7() { | |
// it's bad practice - since we used global scope, instead of activity scope | |
/* | |
* 2020-09-16 00:43:55.669 14849-14849/com.example.croutinesdemo I/System.out: yup hello from main | |
2020-09-16 00:43:59.872 14849-14903/com.example.croutinesdemo I/System.out: yup: still running! | |
2020-09-16 00:44:00.875 14849-14903/com.example.croutinesdemo I/System.out: yup: still running! | |
2020-09-16 00:44:01.877 14849-14903/com.example.croutinesdemo I/System.out: yup: still running! | |
2020-09-16 00:44:02.881 14849-14903/com.example.croutinesdemo I/System.out: yup: still running! | |
2020-09-16 00:44:03.884 14849-14904/com.example.croutinesdemo I/System.out: yup: still running! | |
2020-09-16 00:44:04.893 14849-14903/com.example.croutinesdemo I/System.out: yup: still running! | |
2020-09-16 00:44:05.895 14849-14903/com.example.croutinesdemo I/System.out: yup: still running! | |
2020-09-16 00:44:06.897 14849-14903/com.example.croutinesdemo I/System.out: yup: still running! | |
2020-09-16 00:44:07.900 14849-14903/com.example.croutinesdemo I/System.out: yup: still running! | |
2020-09-16 00:44:08.903 14849-14903/com.example.croutinesdemo I/System.out: yup: still running! | |
2020-09-16 00:44:09.907 14849-14903/com.example.croutinesdemo I/System.out: yup: still running! | |
2020-09-16 00:44:10.910 14849-14903/com.example.croutinesdemo I/System.out: yup: still running! | |
2020-09-16 00:44:11.912 14849-14903/com.example.croutinesdemo I/System.out: yup: still running! | |
2020-09-16 00:44:12.915 14849-14903/com.example.croutinesdemo I/System.out: yup: still running! | |
2020-09-16 00:44:13.929 14849-14903/com.example.croutinesdemo I/System.out: yup: still running! | |
2020-09-16 00:44:14.932 14849-14903/com.example.croutinesdemo I/System.out: yup: still running! | |
2020-09-16 00:44:15.934 14849-14903/com.example.croutinesdemo I/System.out: yup: still running! | |
2020-09-16 00:44:16.936 14849-14903/com.example.croutinesdemo I/System.out: yup: still running! | |
2020-09-16 00:44:17.939 14849-14903/com.example.croutinesdemo I/System.out: yup: still running! | |
2020-09-16 00:44:18.944 14849-14903/com.example.croutinesdemo I/System.out: yup: still running! | |
2020-09-16 00:44:21.576 14849-14903/com.example.croutinesdemo I/System.out: yup: still running! | |
* */ | |
tvDummy.setOnClickListener { | |
// bad practice | |
GlobalScope.launch { | |
while (true) { | |
delay(1000L) | |
println("yup: still running!") | |
} | |
} | |
// launch another coroutine | |
GlobalScope.launch { | |
delay(5000L) | |
startActivity(Intent(this@MainActivity, SecondActivity::class.java)) | |
finish() | |
} | |
} | |
} | |
private fun asyncAwait3Demo6() { | |
// this is BEST practice | |
GlobalScope.launch(Dispatchers.IO) { | |
val time = measureTimeMillis { | |
val ans1: Deferred<String> = async { doNetworkCall1() } | |
val ans2: Deferred<String> = async { doNetworkCall2() } | |
println("yup: ans1: ${ans1.await()}") | |
println("yup: ans2: ${ans2.await()}") | |
} | |
println("yup it took: $time ms!") // 3 sec - which is desirable | |
} | |
} | |
private fun asyncAwait2Demo6() { | |
// this is BAD practice | |
GlobalScope.launch(Dispatchers.IO) { | |
val time = measureTimeMillis { | |
var ans1: String? = null | |
var ans2: String? = null | |
val job1 = launch { ans1 = doNetworkCall1() } | |
val job2 = launch { ans2 = doNetworkCall2() } | |
job1.join() | |
job2.join() | |
println("yup: ans1: $ans1") | |
println("yup: ans2: $ans2") | |
} | |
println("yup it took: $time ms!") // 3 secs - each request executes async but more boiler plate code | |
} | |
} | |
private fun asyncAwait1Demo6() { | |
// this is BAD practice | |
/* | |
* 2020-09-16 00:18:18.177 14066-14066/com.example.croutinesdemo I/System.out: yup hello from main | |
2020-09-16 00:18:24.566 14066-14117/com.example.croutinesdemo I/System.out: yup: resp1: this is resp1 | |
2020-09-16 00:18:24.567 14066-14117/com.example.croutinesdemo I/System.out: yup: resp2: this is resp2 | |
2020-09-16 00:18:24.567 14066-14117/com.example.croutinesdemo I/System.out: yup it took: 6082 ms! | |
* */ | |
// it'll take tot 6 secs to print result | |
GlobalScope.launch(Dispatchers.IO) { | |
val time = measureTimeMillis { | |
val resp1 = doNetworkCall1() // 3 sec | |
val resp2 = doNetworkCall2() // 3 sec | |
println("yup: resp1: $resp1") | |
println("yup: resp2: $resp2") | |
} | |
println("yup it took: $time ms!") // 6 secs - which is undesirable | |
} | |
} | |
private fun jobCancel4Demo5() { | |
/* | |
* with timeout | |
* | |
* | |
* 2020-09-15 23:28:18.585 13481-13481/com.example.croutinesdemo I/System.out: yup hello from main | |
2020-09-15 23:28:18.844 13481-13535/com.example.croutinesdemo I/System.out: yup: coroutine started! | |
2020-09-15 23:28:20.721 13481-13535/com.example.croutinesdemo I/System.out: yup: fib calculated, for i: 30, res: 832040 | |
2020-09-15 23:28:20.755 13481-13535/com.example.croutinesdemo I/System.out: yup: fib calculated, for i: 31, res: 1346269 | |
2020-09-15 23:28:20.820 13481-13535/com.example.croutinesdemo I/System.out: yup: fib calculated, for i: 32, res: 2178309 | |
2020-09-15 23:28:20.889 13481-13535/com.example.croutinesdemo I/System.out: yup: fib calculated, for i: 33, res: 3524578 | |
2020-09-15 23:28:21.023 13481-13535/com.example.croutinesdemo I/System.out: yup: fib calculated, for i: 34, res: 5702887 | |
2020-09-15 23:28:21.298 13481-13535/com.example.croutinesdemo I/System.out: yup: fib calculated, for i: 35, res: 9227465 | |
2020-09-15 23:28:21.842 13481-13535/com.example.croutinesdemo I/System.out: yup: fib calculated, for i: 36, res: 14930352 | |
2020-09-15 23:28:21.842 13481-13535/com.example.croutinesdemo I/System.out: yup: coroutine ended! | |
* */ | |
GlobalScope.launch(Dispatchers.Default) { | |
println("yup: coroutine started!") | |
withTimeout(1000L) { // cancels automatically after 1sec | |
// long running work | |
for (i in 30..40) { | |
if (isActive) | |
println("yup: fib calculated, for i: $i, res: ${fib(i)}") | |
} | |
} | |
println("yup: coroutine ended!") | |
} | |
} | |
private fun jobCancel3Demo5() { | |
/* | |
* | |
* it's cancelling properly | |
* 2020-09-15 23:23:32.312 13222-13222/com.example.croutinesdemo I/System.out: yup hello from main | |
2020-09-15 23:23:32.313 13222-13275/com.example.croutinesdemo I/System.out: yup: coroutine started! | |
2020-09-15 23:23:32.338 13222-13275/com.example.croutinesdemo I/System.out: yup: fib calculated, for i: 30, res: 832040 | |
2020-09-15 23:23:32.365 13222-13275/com.example.croutinesdemo I/System.out: yup: fib calculated, for i: 31, res: 1346269 | |
2020-09-15 23:23:32.412 13222-13275/com.example.croutinesdemo I/System.out: yup: fib calculated, for i: 32, res: 2178309 | |
2020-09-15 23:23:32.467 13222-13275/com.example.croutinesdemo I/System.out: yup: fib calculated, for i: 33, res: 3524578 | |
2020-09-15 23:23:32.573 13222-13275/com.example.croutinesdemo I/System.out: yup: fib calculated, for i: 34, res: 5702887 | |
2020-09-15 23:23:32.774 13222-13275/com.example.croutinesdemo I/System.out: yup: fib calculated, for i: 35, res: 9227465 | |
2020-09-15 23:23:33.017 13222-13275/com.example.croutinesdemo I/System.out: yup: fib calculated, for i: 36, res: 14930352 | |
2020-09-15 23:23:33.314 13222-13275/com.example.croutinesdemo I/System.out: yup: fib calculated, for i: 37, res: 24157817 | |
2020-09-15 23:23:33.314 13222-13222/com.example.croutinesdemo I/System.out: yup: cancel called! | |
2020-09-15 23:23:33.314 13222-13222/com.example.croutinesdemo I/System.out: yup: main thread continuing it's work! | |
2020-09-15 23:23:33.958 13222-13275/com.example.croutinesdemo I/System.out: yup: fib calculated, for i: 38, res: 39088169 | |
2020-09-15 23:23:33.958 13222-13275/com.example.croutinesdemo I/System.out: yup: coroutine ended! | |
* */ | |
val job = GlobalScope.launch(Dispatchers.Default) { | |
println("yup: coroutine started!") | |
// long running work | |
for (i in 30..40) { | |
if (isActive) | |
println("yup: fib calculated, for i: $i, res: ${fib(i)}") | |
} | |
println("yup: coroutine ended!") | |
} | |
runBlocking { | |
delay(1000L) | |
job.cancel() | |
println("yup: cancel called!") | |
println("yup: main thread continuing it's work!") | |
} | |
} | |
private fun jobCancel2Demo5() { | |
/* | |
it's not getting cancelled, because coroutine is busy doing the calculation within the loop | |
* | |
* 2020-09-15 23:20:42.064 13102-13102/com.example.croutinesdemo I/System.out: yup hello from main | |
2020-09-15 23:20:42.162 13102-13161/com.example.croutinesdemo I/System.out: yup: coroutine started! | |
2020-09-15 23:20:42.182 13102-13161/com.example.croutinesdemo I/System.out: yup: fib calculated, for i: 30, res: 832040 | |
2020-09-15 23:20:42.210 13102-13161/com.example.croutinesdemo I/System.out: yup: fib calculated, for i: 31, res: 1346269 | |
2020-09-15 23:20:42.242 13102-13161/com.example.croutinesdemo I/System.out: yup: fib calculated, for i: 32, res: 2178309 | |
2020-09-15 23:20:42.303 13102-13161/com.example.croutinesdemo I/System.out: yup: fib calculated, for i: 33, res: 3524578 | |
2020-09-15 23:20:42.370 13102-13161/com.example.croutinesdemo I/System.out: yup: fib calculated, for i: 34, res: 5702887 | |
2020-09-15 23:20:42.500 13102-13161/com.example.croutinesdemo I/System.out: yup: fib calculated, for i: 35, res: 9227465 | |
2020-09-15 23:20:42.699 13102-13161/com.example.croutinesdemo I/System.out: yup: fib calculated, for i: 36, res: 14930352 | |
2020-09-15 23:20:43.002 13102-13161/com.example.croutinesdemo I/System.out: yup: fib calculated, for i: 37, res: 24157817 | |
2020-09-15 23:20:43.181 13102-13102/com.example.croutinesdemo I/System.out: yup: cancel called! | |
2020-09-15 23:20:43.181 13102-13102/com.example.croutinesdemo I/System.out: yup: main thread continuing it's work! | |
2020-09-15 23:20:43.515 13102-13161/com.example.croutinesdemo I/System.out: yup: fib calculated, for i: 38, res: 39088169 | |
2020-09-15 23:20:44.304 13102-13161/com.example.croutinesdemo I/System.out: yup: fib calculated, for i: 39, res: 63245986 | |
2020-09-15 23:20:45.563 13102-13161/com.example.croutinesdemo I/System.out: yup: fib calculated, for i: 40, res: 102334155 | |
2020-09-15 23:20:45.563 13102-13161/com.example.croutinesdemo I/System.out: yup: coroutine ended! | |
* | |
* */ | |
val job = GlobalScope.launch(Dispatchers.Default) { | |
println("yup: coroutine started!") | |
// long running work | |
for (i in 30..40) { | |
println("yup: fib calculated, for i: $i, res: ${fib(i)}") | |
} | |
println("yup: coroutine ended!") | |
} | |
runBlocking { | |
delay(1000L) | |
job.cancel() | |
println("yup: cancel called!") | |
println("yup: main thread continuing it's work!") | |
} | |
} | |
private fun fib(n: Int): Int { | |
return if (n == 0) 0 | |
else if (n == 1) 1 | |
else fib(n - 1) + fib(n - 2) | |
} | |
private fun jobCancelDemo5() { | |
/* | |
* 2020-09-15 23:14:21.792 12876-12876/com.example.croutinesdemo I/System.out: yup hello from main | |
2020-09-15 23:14:21.888 12876-12911/com.example.croutinesdemo I/System.out: yup: this coroutine is running! | |
2020-09-15 23:14:22.902 12876-12911/com.example.croutinesdemo I/System.out: yup: this coroutine is running! | |
2020-09-15 23:14:23.905 12876-12876/com.example.croutinesdemo I/System.out: yup: job cancelled! | |
2020-09-15 23:14:23.905 12876-12876/com.example.croutinesdemo I/System.out: yup: main thread is continuing! | |
* */ | |
val job = GlobalScope.launch(Dispatchers.IO) { | |
repeat(5) { | |
println("yup: this coroutine is running!") | |
delay(1000L) | |
} | |
} | |
runBlocking { | |
delay(2000L) | |
job.cancel() | |
println("yup: job cancelled!") | |
println("yup: main thread is continuing!") | |
} | |
} | |
private fun jobJoinDemo5() { | |
/* | |
* 2020-09-15 23:03:47.041 12085-12085/com.example.croutinesdemo I/System.out: yup hello from main | |
2020-09-15 23:03:47.275 12085-12144/com.example.croutinesdemo I/System.out: yup: CoRoutine is running! | |
2020-09-15 23:03:48.298 12085-12144/com.example.croutinesdemo I/System.out: yup: CoRoutine is running! | |
2020-09-15 23:03:49.301 12085-12144/com.example.croutinesdemo I/System.out: yup: CoRoutine is running! | |
2020-09-15 23:03:50.313 12085-12144/com.example.croutinesdemo I/System.out: yup: CoRoutine is running! | |
2020-09-15 23:03:51.316 12085-12144/com.example.croutinesdemo I/System.out: yup: CoRoutine is running! | |
2020-09-15 23:03:52.322 12085-12085/com.example.croutinesdemo I/System.out: yup: main thread continuing! | |
* */ | |
val job = GlobalScope.launch(Dispatchers.Default) { | |
repeat(5) { | |
println("yup: CoRoutine is running!") | |
delay(1000L) | |
} | |
} | |
runBlocking { | |
job.join() | |
println("yup: main thread continuing!") | |
} | |
} | |
private fun runBlockingDemo4() { | |
// 1 | |
// create coroutine in main thread or whatever thread, and blocks the respective thread | |
// println("yup before run blocking") | |
// runBlocking { | |
// println("yup inside run blocking, before delay") | |
// delay(5000L) | |
// println("yup inside run blocking, after delay") | |
// } | |
// println("yup after run blocking") | |
// 2 | |
// runBlocking { | |
// /* | |
// * o/p | |
// * 2020-09-15 21:50:06.557 11180-11180/com.example.croutinesdemo I/System.out: yup hello from main | |
// 2020-09-15 21:50:06.558 11180-11180/com.example.croutinesdemo I/System.out: yup 2nd inside run blocking, before delay | |
// 2020-09-15 21:50:09.560 11180-11235/com.example.croutinesdemo I/System.out: yup finished IO co routine | |
// 2020-09-15 21:50:11.561 11180-11180/com.example.croutinesdemo I/System.out: yup 2nd inside run blocking, after delay | |
// * */ | |
// launch(Dispatchers.IO) { | |
// delay(3000L) | |
// println("yup finished IO co routine") | |
// } | |
// println("yup 2nd inside run blocking, before delay") | |
// delay(5000L) | |
// println("yup 2nd inside run blocking, after delay") | |
// } | |
// 3 | |
runBlocking { | |
/* | |
* o/p | |
2020-09-15 21:51:52.771 11319-11319/com.example.croutinesdemo I/System.out: yup hello from main | |
2020-09-15 21:51:52.909 11319-11319/com.example.croutinesdemo I/System.out: yup 2nd inside run blocking, before delay | |
2020-09-15 21:51:57.978 11319-11319/com.example.croutinesdemo I/System.out: yup 2nd inside run blocking, after delay | |
2020-09-15 21:52:00.987 11319-11371/com.example.croutinesdemo I/System.out: yup finished IO co routine | |
* */ | |
println("yup 2nd inside run blocking, before delay") | |
delay(5000L) | |
launch(Dispatchers.IO) { | |
delay(3000L) | |
println("yup finished IO co routine") | |
} | |
println("yup 2nd inside run blocking, after delay") | |
} | |
} | |
private fun contextSwitching3() { | |
GlobalScope.launch(Dispatchers.Main) { | |
// updating UI | |
println("yup: I'm CoRoutine that runs in Main Thread: ${Thread.currentThread().name}") | |
} | |
GlobalScope.launch(Dispatchers.IO) { | |
// api calls, db operation, file r/w etc | |
println("yup: I'm CoRoutine that runs in worker Thread: ${Thread.currentThread().name}") | |
} | |
GlobalScope.launch(Dispatchers.Default) { | |
// such as sorting 10,000 items in list | |
println("yup: I'm CoRoutine that runs in worker Thread, suitable for long running process: ${Thread.currentThread().name}") // let the thread name = `worker2` | |
GlobalScope.launch(Dispatchers.Unconfined) { | |
// not confined to any thread, it'll run in the thread where this launch/suspend function is called | |
println("yup: I'm CoRoutine that runs in UnConfined Thread: ${Thread.currentThread().name}") // this coroutine will run in thread `worker2` | |
} | |
} | |
// GlobalScope.launch(Dispatchers.Unconfined) { | |
// // not confined to any thread, it'll run in `main` thread | |
// println("yup: I'm CoRoutine that runs in UnConfined Thread: ${Thread.currentThread().name}") | |
// } | |
GlobalScope.launch(newSingleThreadContext("coroutine will work in this thread!")) { | |
println("yup: I'm CoRoutine that runs in specified Thread: ${Thread.currentThread().name}") | |
} | |
// network call simulation | |
GlobalScope.launch(Dispatchers.IO) { | |
println("yup: sim n/w call I'm CoRoutine that runs in worker Thread: ${Thread.currentThread().name}") | |
val resp = doNetworkCall1() | |
withContext(Dispatchers.Main) { | |
println("yup: sim n/w call I'm CoRoutine that runs in main Thread: ${Thread.currentThread().name}") | |
tvDummy.text = resp | |
} | |
} | |
} | |
private fun suspendFunc2() { | |
GlobalScope.launch { | |
val resp1 = doNetworkCall1() | |
val resp2 = doNetworkCall2() | |
println("yup res resp1: $resp1") | |
println("yup res resp2: $resp2") | |
} | |
} | |
private suspend fun doNetworkCall1(): String { | |
delay(3000L) | |
return "this is resp1" | |
} | |
private suspend fun doNetworkCall2(): String { | |
delay(3000L) | |
return "this is resp2" | |
} | |
private fun basicCoroutine1() { | |
/* | |
* O/P | |
* | |
* 2020-09-15 23:00:56.531 11965-11965/com.example.croutinesdemo I/System.out: yup hello from main | |
2020-09-15 23:00:59.538 11965-12004/com.example.croutinesdemo I/System.out: yup hello from DefaultDispatcher-worker-1 | |
* */ | |
GlobalScope.launch { // launches co routine, that lives for whole application life time | |
delay(3000L) | |
println("yup hello from ${Thread.currentThread().name}") | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.example.croutinesdemo | |
import androidx.appcompat.app.AppCompatActivity | |
class SecondActivity : AppCompatActivity() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment