Skip to content

Instantly share code, notes, and snippets.

@sav007
Last active November 13, 2018 18:28
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sav007/acb3d66a4262404170c5e2e7d7156027 to your computer and use it in GitHub Desktop.
Save sav007/acb3d66a4262404170c5e2e7d7156027 to your computer and use it in GitHub Desktop.
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")
}
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")
}
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>
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())
}
}
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;
}
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")
}
}
}
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")
}
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")
}
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)
}
}
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")
}
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()
}
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