Last active
November 13, 2018 18:28
-
-
Save sav007/acb3d66a4262404170c5e2e7d7156027 to your computer and use it in GitHub Desktop.
This file contains 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.shopify.coroutine.sample | |
import kotlinx.coroutines.delay | |
import kotlinx.coroutines.isActive | |
import kotlinx.coroutines.runBlocking | |
import kotlin.coroutines.coroutineContext | |
fun main(vararg args: String) { | |
// suspendFunc1() //- won't compile outside coroutine or another suspend function | |
// coroutine builder | |
runBlocking { | |
suspendFunc1() // call suspend function from coroutine | |
} | |
println("all done") | |
} | |
private suspend fun suspendFunc1() { | |
if (coroutineContext.isActive) { | |
println("coroutine is active") | |
} | |
suspendFunc2() // call another suspend functions | |
regularFunc() // call regular functions | |
println("suspend function 1 - done") | |
} | |
private suspend fun suspendFunc2() { | |
delay(500) // stdlib coroutine suspend function | |
println("suspend function 2 - done") | |
} | |
private fun regularFunc() { | |
println("regular - done") | |
} |
This file contains 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.shopify.coroutine.sample | |
import kotlinx.coroutines.* | |
import java.lang.Exception | |
import java.lang.IllegalArgumentException | |
import java.lang.RuntimeException | |
// unidirectional cancelation | |
fun main(vararg args: String) { | |
try { | |
runBlocking { | |
supervisorScope { | |
val firstCoroutine = async { | |
delay(300) | |
println("crashing first coroutine") | |
throw IllegalArgumentException() | |
} | |
launch(Dispatchers.Default) { | |
try { | |
delay(700) | |
println("second coroutine scope still alive") | |
} catch (e: Exception) { | |
println("second coroutine scope $e") | |
} | |
} | |
try { | |
firstCoroutine.await() | |
} catch (e: Exception) { | |
println("first coroutine try $e") | |
} | |
// delay(300) | |
delay(900) | |
println("crashing scope") | |
throw RuntimeException() | |
} | |
} | |
} catch (e: Exception) { | |
println("runBlocking try $e") | |
} | |
println("all done") | |
} |
This file contains 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.shopify.coroutine.sample | |
import kotlinx.coroutines.* | |
import kotlin.coroutines.CoroutineContext | |
import kotlin.coroutines.coroutineContext | |
fun main(vararg args: String) { | |
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) { | |
println("Default : I'm working in thread ${Thread.currentThread().name}") | |
} | |
launch(newSingleThreadContext("MyOwnThread")) { | |
println("newSingleThreadContext: I'm working in thread ${Thread.currentThread().name}") | |
} | |
// shared with Default | |
launch(Dispatchers.IO) { | |
println("IO: I'm working in thread ${Thread.currentThread().name}") | |
} | |
// switch context | |
launch(Dispatchers.Default) { | |
println("withContext: I'm working in thread ${Thread.currentThread().name}") | |
withContext(newSingleThreadContext("WithContext")) { | |
println("withContext: I'm working in thread ${Thread.currentThread().name}") | |
} | |
} | |
launch(Dispatchers.Default + User("Ivan")) { | |
println("job: ${coroutineContext[Job]}") | |
sayHello() | |
} | |
} | |
} | |
private suspend fun sayHello() { | |
println("hello ${coroutineContext[UserKey]!!.name}") | |
} | |
private data class User(val name: String) : CoroutineContext.Element { | |
override val key: CoroutineContext.Key<*> | |
get() = UserKey | |
} | |
private object UserKey : CoroutineContext.Key<User> |
This file contains 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.shopify.coroutine.sample | |
import kotlinx.coroutines.* | |
import java.lang.IllegalStateException | |
import kotlin.coroutines.resume | |
import kotlin.coroutines.resumeWithException | |
import kotlin.coroutines.suspendCoroutine | |
fun main(vararg args: String) { | |
launch() // will not block thread | |
println("continue execution") // will be called without waiting for launch | |
async() // will not block thread | |
println("still continue execution") // will be called without waiting for async | |
blocking() // will block thread | |
println("all done") // wait for blocking to be finished | |
} | |
// launch and forget, designated for side effects | |
private fun launch() = GlobalScope.launch { | |
delay(200) | |
println("launch - done") | |
} | |
// must return result, like future | |
private fun async() = GlobalScope.async { | |
delay(200) | |
println("async - done") | |
"OK" | |
} | |
// blocks current thread and wait for complition | |
private fun blocking() = runBlocking { | |
println("runBlocking - start") | |
delay(600) | |
suspendCoroutine() | |
println("runBlocking - done") | |
} | |
// integration with 3rd party libs that doesn't support coroutines | |
private suspend fun suspendCoroutine(): String { | |
delay(200) | |
return suspendCancellableCoroutine { continuation -> | |
continuation.invokeOnCancellation { | |
// cleanup resources | |
} | |
println("suspend coroutine - done") | |
continuation.resume("Ok") | |
// continuation.resumeWithException(IllegalStateException()) | |
} | |
} |
This file contains 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.shopify.coroutine.sample | |
import kotlinx.coroutines.* | |
fun main(vararg args: String) { | |
runBlocking { | |
val launchJob = launch() // won't block | |
println("continue after launch") | |
val async1Job = async1() // won't block | |
println("continue after async1") | |
val async2Job = async2() // won't block | |
println("continue after async2") | |
launchJob.join() // will block now | |
println("continue after launch done") | |
println("start async2") | |
async2Job.start() // explicitly start lazy coroutine execution | |
val result1 = async1Job.await() // will block now | |
val result2 = async2Job.await() // will block now | |
println("continue after await with $result1 : $result2") | |
} | |
println("all done") | |
} | |
// launch and forget, doesn't carry the result | |
private fun launch(): Job = GlobalScope.launch { | |
delay(400) | |
println("launch - done") | |
} | |
// future, promises to deliver a results | |
private fun async1(): Deferred<Result> = GlobalScope.async { | |
delay(200) | |
println("async1 - done") | |
Result.SUCCESS | |
} | |
// lazy start, won't start unless call join / await or explicit start | |
private fun async2(): Deferred<Result> = GlobalScope.async(start = CoroutineStart.LAZY) { | |
delay(200) | |
println("async2 - done") | |
Result.FAILURE | |
} | |
enum class Result { | |
SUCCESS, FAILURE; | |
} |
This file contains 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.shopify.coroutine.sample | |
import kotlinx.coroutines.* | |
// deprecate since 0.30 and removed from 1.0 | |
// launch { ... } | |
// async { ... } | |
fun main(vararg args: String) { | |
// globalScope() | |
// parentScope() | |
customScope() | |
println("all done") | |
} | |
// runBlocking won't wait for child coroutine to finish due to the GlobalScope | |
// global scoped coroutines like Thread daemons | |
private fun globalScope() = runBlocking { | |
GlobalScope.launch { | |
delay(500) | |
println("launch - done") | |
} | |
} | |
// runBlocking for all children coroutines are finished | |
private fun parentScope() = runBlocking { | |
launch { | |
delay(500) | |
println("launch - done") | |
} | |
} | |
// runBlocking wait until all children scopes are finished | |
// child scopes does not block the current thread | |
private fun customScope() = runBlocking<Unit> { | |
println("starting first scope") | |
coroutineScope { | |
launch { | |
delay(500) | |
println("first launch - done") | |
} | |
} | |
// will be called immediately | |
println("starting second scope") | |
coroutineScope { | |
launch { | |
delay(800) | |
println("second launch - done") | |
} | |
} | |
} |
This file contains 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.shopify.coroutine.sample | |
import kotlinx.coroutines.* | |
fun main(vararg args: String) { | |
runBlocking { | |
// launch / async returns a Job that can be canceled | |
val job = launch { | |
while (true) { | |
delay(300) | |
println("working") | |
} | |
println("WTF") | |
} | |
delay(900) | |
println("trying to cancel job") | |
job.cancelAndJoin() | |
} | |
println("all done") | |
} |
This file contains 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.shopify.coroutine.sample | |
import kotlinx.coroutines.* | |
// trick used in example with VM with coroutines | |
fun main(vararg args: String) { | |
runBlocking { | |
val parentJob = Job() | |
println("before launch job: $parentJob") | |
launch(Dispatchers.Default + parentJob) { | |
println("parent launch job: ${coroutineContext[Job]}") // each coroutine has own Job with ref to parent | |
// Job(parent: Job? = null) | |
launch { | |
println("child launch job1: ${coroutineContext[Job]}") | |
while (true) { | |
delay(200) | |
println("working1") | |
} | |
} | |
launch { | |
println("child launch job2: ${coroutineContext[Job]}") | |
while (true) { | |
delay(300) | |
println("working2") | |
} | |
} | |
} | |
delay(600) | |
println("trying to cancel via parent job") | |
parentJob.cancel() | |
} | |
println("all done") | |
} |
This file contains 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.shopify.coroutine.sample | |
import kotlinx.coroutines.* | |
import kotlin.coroutines.resume | |
import kotlin.coroutines.suspendCoroutine | |
fun main(vararg args: String) { | |
runBlocking { | |
val job = doWork() | |
delay(500) | |
println("trying to cancel job") | |
job.cancelAndJoin() | |
} | |
println("all done") | |
} | |
private suspend fun CoroutineScope.doWork() = launch(Dispatchers.Default) { | |
var nextCallTime = System.currentTimeMillis() | |
while (isActive) { // && | |
// delay(300) // | |
yield() | |
if (System.currentTimeMillis() >= nextCallTime) { | |
suspendCoroutine() | |
// suspendCancellableCoroutine() | |
println("working") | |
nextCallTime += 300L | |
} | |
} | |
println("WTF") | |
} | |
// will trigger CancellationException on continuation.resume(Unit) if parent coroutine canceled | |
private suspend fun suspendCancellableCoroutine() { | |
return suspendCancellableCoroutine { continuation -> | |
continuation.resume(Unit) | |
} | |
} | |
// will ignore the fact of cancellation parent coroutine and keep going | |
private suspend fun suspendCoroutine() { | |
return suspendCoroutine { continuation -> | |
continuation.resume(Unit) | |
} | |
} |
This file contains 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.shopify.coroutine.sample | |
import kotlinx.coroutines.* | |
import java.lang.Exception | |
import java.lang.IllegalArgumentException | |
fun main(vararg args: String) { | |
try { | |
runBlocking { | |
coroutineScope { | |
launch(Dispatchers.Default) { | |
try { | |
delay(600) | |
println("first coroutine scope still alive") | |
} catch (e: Exception) { | |
println("first coroutine scope $e") | |
} | |
} | |
} | |
try { | |
coroutineScope { | |
val job = launch { | |
delay(300) | |
throw IllegalArgumentException() | |
} | |
// val job = async { | |
// delay(300) | |
// throw IllegalArgumentException() | |
// } | |
launch(Dispatchers.Default) { | |
try { | |
delay(600) | |
println("second coroutine scope still alive") | |
} catch (e: Exception) { | |
println("second coroutine scope $e") | |
} | |
} | |
// will never give you the original cause | |
try { | |
job.join() | |
} catch (e: Exception) { | |
println("failed job $e") | |
} | |
// // will provide you the original cause | |
// try { | |
// job.await() | |
// } catch (e: Exception) { | |
// println("failed job $e") | |
// } | |
} | |
} catch (e: Exception) { | |
println("coroutineScope try $e") | |
} | |
} | |
} catch (e: Exception) { | |
println("runBlocking try $e") | |
} | |
println("all done") | |
} |
This file contains 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.shopify.coroutine.sample | |
import kotlinx.coroutines.* | |
import java.lang.Exception | |
import java.lang.IllegalArgumentException | |
// 1. launch crashes the thread if exception handler not installed | |
// 2. even if you call join and wrap it into try catch launch still crashes the thread | |
// 3. async doesn't crash the thread | |
// 4. async doesn't accept the exception handler | |
// 5. async / launch won't crash the parent scope | |
fun main(vararg args: String) { | |
try { | |
runBlocking { | |
// val job = launch() | |
val job = async() | |
try { | |
launch { | |
delay(600) | |
println("second coroutine still alive") | |
}.join() | |
} catch (e: Exception) { | |
println("second coroutine try $e") | |
} | |
// try { | |
// job.join() | |
// } catch (e: Exception) { | |
// println("first coroutine try $e") | |
// } | |
try { | |
job.await() | |
} catch (e: Exception) { | |
println("first coroutine try $e") | |
} | |
} | |
} catch (e: Exception) { | |
println("runBlocking try $e") | |
} | |
println("all done") | |
} | |
val exceptionHandler = CoroutineExceptionHandler { _, exception -> | |
println("exception handler $exception") | |
} | |
private fun launch(): Job = GlobalScope.launch(exceptionHandler) { | |
delay(300) | |
println("crashing first coroutine") | |
throw IllegalArgumentException() | |
} | |
// doesn't make any sense to install custom CoroutineExceptionHandler | |
private fun async(): Deferred<String> = GlobalScope.async(exceptionHandler) { | |
delay(300) | |
println("crashing first coroutine") | |
throw IllegalArgumentException() | |
} |
This file contains 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
apply plugin: 'com.android.application' | |
apply plugin: 'kotlin-android' | |
apply plugin: 'kotlin-android-extensions' | |
android { | |
compileSdkVersion 28 | |
defaultConfig { | |
applicationId "sample.coroutine.shopify.com.coroutinesample" | |
minSdkVersion 21 | |
targetSdkVersion 28 | |
versionCode 1 | |
versionName "1.0" | |
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" | |
} | |
buildTypes { | |
release { | |
minifyEnabled false | |
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' | |
} | |
} | |
} | |
dependencies { | |
implementation fileTree(dir: 'libs', include: ['*.jar']) | |
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" | |
implementation 'com.android.support:appcompat-v7:28.0.0' | |
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.0.0' | |
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.0.0' | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment