Skip to content

Commit 3abc81a

Browse files
Add some more playground files
1 parent 3d725da commit 3abc81a

File tree

16 files changed

+404
-9
lines changed

16 files changed

+404
-9
lines changed
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package com.lukaslechner.coroutineusecasesonandroid.playground.channels
2+
3+
import kotlinx.coroutines.CoroutineScope
4+
import kotlinx.coroutines.GlobalScope
5+
import kotlinx.coroutines.channels.consumeEach
6+
import kotlinx.coroutines.channels.produce
7+
import kotlinx.coroutines.delay
8+
import kotlinx.coroutines.launch
9+
import kotlin.random.Random
10+
11+
12+
fun main() {
13+
GlobalScope.launch {
14+
produceRandom().consumeEach { println(it) }
15+
println("All values consumed")
16+
}
17+
18+
println("main() finished")
19+
Thread.sleep(1000)
20+
}
21+
22+
// whereas flow() is a top level function => produce is defined on CoroutineScope
23+
private fun CoroutineScope.produceRandom() = produce {
24+
repeat(5) {
25+
delay(100)
26+
send(Random.nextInt())
27+
}
28+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package com.lukaslechner.coroutineusecasesonandroid.playground.channels
2+
3+
import kotlinx.coroutines.CoroutineScope
4+
import kotlinx.coroutines.channels.consumeEach
5+
import kotlinx.coroutines.channels.produce
6+
import kotlinx.coroutines.delay
7+
import kotlinx.coroutines.runBlocking
8+
import kotlin.random.Random
9+
10+
fun main() = runBlocking {
11+
12+
val getRandomIntsChannel = generateRandom()
13+
14+
delay(500)
15+
16+
getRandomIntsChannel.consumeEach {
17+
// with offer, we will only consume 5-6 offered items
18+
println("Random number $it consumed")
19+
}
20+
21+
println("Done!")
22+
}
23+
24+
// Return Type is ReceiveChannel
25+
private fun CoroutineScope.generateRandom() = produce {
26+
repeat(10) {
27+
delay(100)
28+
29+
// emit in flows or send in channels will suspend until someone can receive the item
30+
// send(Random.nextInt())
31+
offer(Random.nextInt())
32+
}
33+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package com.lukaslechner.coroutineusecasesonandroid.playground.channels
2+
3+
import kotlinx.coroutines.*
4+
import kotlinx.coroutines.channels.Channel
5+
import kotlinx.coroutines.channels.consumeEach
6+
import kotlin.random.Random
7+
8+
9+
fun main() = runBlocking {
10+
11+
// Buffer of a default size of 64 elements
12+
val channel = Channel<Int>(Channel.BUFFERED)
13+
14+
val job1 = GlobalScope.launch(Dispatchers.Default) {
15+
repeat(3) {
16+
delay(500)
17+
channel.send(Random.nextInt(1, 100))
18+
}
19+
20+
channel.close()
21+
}
22+
23+
val job2 = GlobalScope.launch() {
24+
channel.consumeEach {
25+
println(it)
26+
println("Consumed")
27+
}
28+
}
29+
30+
joinAll(job1, job2)
31+
}

app/src/main/java/com/lukaslechner/coroutineusecasesonandroid/playground/flow/1-Simple-Flows.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,16 @@ import kotlinx.coroutines.runBlocking
1010
// Sequence for synchronously computed values
1111
// Flow for asynchronously computed values
1212

13+
// flow() sets up a coroutine for you to use, so you do not need to worry about doing that yourself
1314
private fun simple(): Flow<Int> = flow { // flow builder
1415
for (i in 1..3) {
1516
delay(100) // pretend we are doing something useful here
1617
emit(i) // emit next value
1718
}
1819
}
1920

21+
// when you exit the lambda expression, the flow is considered to be closed.
22+
2023
fun main() = runBlocking<Unit> {
2124
// Launch a concurrent coroutine to check if the main thread is blocked
2225
launch {

app/src/main/java/com/lukaslechner/coroutineusecasesonandroid/playground/flow/12-FlowOn-operator.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,12 @@ private fun simple(): Flow<Int> = flow {
1919

2020
// flowOn creates another coroutine for an upstream flow when it has to change the CoroutineDispatcher in its context
2121

22+
// Notice how flow{} works in the background thread, while collection happens in the main thread.
23+
24+
// Another thing to observe here is that the flowOn operator has changed the default sequential nature of the flow.
25+
// Now, collection happens in one coroutine, and emission happens in another coroutine that is running in another thread concurrently with
26+
// the collecting coroutine
27+
2228
fun main() = runBlocking<Unit> {
2329
simple().collect { value ->
2430
log("Collected $value")

app/src/main/java/com/lukaslechner/coroutineusecasesonandroid/playground/flow/7-Size-limiting-operators.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ fun numbers(): Flow<Int> = flow {
1212
emit(2)
1313
println("This line will not execute")
1414
emit(3)
15+
} catch (e: Exception) {
16+
println(e) // kotlinx.coroutines.flow.internal.AbortFlowException: Flow was aborted, no more elements needed
1517
} finally {
1618
println("Finally in numbers")
1719
}

app/src/main/java/com/lukaslechner/coroutineusecasesonandroid/playground/flow/8-Terminal-flow-operators.kt

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ import kotlinx.coroutines.flow.map
55
import kotlinx.coroutines.flow.reduce
66
import kotlinx.coroutines.runBlocking
77

8-
8+
/**
9+
* All terminal operators are suspend functions
10+
*/
911
fun main() = runBlocking {
1012
val sum = (1..5).asFlow()
1113
.map { it * it } // squares of numbers from 1 to 5
@@ -14,6 +16,7 @@ fun main() = runBlocking {
1416
}
1517

1618
// Other Terminal operators
17-
// * toList(), toSet()
18-
// * first()
19-
// * reduce(), flow
19+
// * toList(), toSet() => collects all of the objects emitted by the Flow and returns them in a List or a Set; works for bounded flows, but not for flows that emit object indefinitely
20+
// * reduce(), flow
21+
// * single() => returns first object emitted by the Flow, throws exception if more items are emmited
22+
// * first() => returns one object of the flow and then stops consuming; safe to use with a Flow that might return more than one value
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package com.lukaslechner.coroutineusecasesonandroid.playground.flow.exceptionhandling
2+
3+
import kotlinx.coroutines.CoroutineScope
4+
import kotlinx.coroutines.Dispatchers
5+
import kotlinx.coroutines.Job
6+
import kotlinx.coroutines.flow.flow
7+
import kotlinx.coroutines.flow.launchIn
8+
import kotlinx.coroutines.flow.onEach
9+
import kotlinx.coroutines.runBlocking
10+
11+
fun main() = runBlocking<Unit> {
12+
13+
val someScope = CoroutineScope(Dispatchers.Default)
14+
15+
var job: Job? = null
16+
17+
try {
18+
job = someFlow.onEach {
19+
println("onEach: $it")
20+
}.launchIn(someScope)
21+
} catch (exception: Exception) {
22+
println("Caught: $exception")
23+
}
24+
25+
// launchIn creates a new coroutine, so we can't use try-catch to handle exceptions
26+
27+
job?.join()
28+
}
29+
30+
private val someFlow = flow<Int> {
31+
emit(1)
32+
emit(2)
33+
throw IllegalStateException()
34+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package com.lukaslechner.coroutineusecasesonandroid.playground.flow.operators
2+
3+
import kotlinx.coroutines.delay
4+
import kotlinx.coroutines.flow.collect
5+
import kotlinx.coroutines.flow.flow
6+
import kotlinx.coroutines.flow.sample
7+
import kotlinx.coroutines.runBlocking
8+
9+
private val fastEmittingFlow = flow {
10+
repeat(10) {
11+
emit(it)
12+
delay(110)
13+
}
14+
}
15+
16+
fun main() = runBlocking {
17+
fastEmittingFlow.sample(200).collect {
18+
println("$it")
19+
}
20+
21+
// Returns a flow that emits only the latest value emitted by the original flow during the given sampling period.
22+
23+
// prints: 1,3,5,6,7
24+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package com.lukaslechner.coroutineusecasesonandroid.playground.flow.retry
2+
3+
import kotlinx.coroutines.delay
4+
import kotlinx.coroutines.flow.collect
5+
import kotlinx.coroutines.flow.flow
6+
import kotlinx.coroutines.flow.retry
7+
import kotlinx.coroutines.runBlocking
8+
import kotlin.random.Random
9+
10+
fun main() = runBlocking {
11+
getRandom()
12+
.retry(3)
13+
.collect {
14+
// 4 emissions, 1 initial and 3 retries
15+
println("Collected: $it")
16+
}
17+
}
18+
19+
private fun getRandom() = flow {
20+
repeat(3) {
21+
delay(100)
22+
emit(Random.nextInt())
23+
check(it < 0)
24+
}
25+
}

0 commit comments

Comments
 (0)