Skip to content

Commit 1dcebc5

Browse files
Merge branch 'master' into coroutines_course_empty
2 parents b93b180 + 56f0375 commit 1dcebc5

File tree

16 files changed

+421
-28
lines changed

16 files changed

+421
-28
lines changed

README.md

Lines changed: 71 additions & 26 deletions
Large diffs are not rendered by default.

app/src/main/java/com/lukaslechner/coroutineusecasesonandroid/MainActivity.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,5 +50,5 @@ class MainActivity : BaseActivity() {
5050
return itemDecorator
5151
}
5252

53-
override fun getToolbarTitle() = "Coroutine Usecases on Android"
53+
override fun getToolbarTitle() = "Coroutines and Flows on Android"
5454
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package com.lukaslechner.coroutineusecasesonandroid.playground.flow.channels
2+
3+
import kotlinx.coroutines.channels.Channel
4+
import kotlinx.coroutines.channels.consumeEach
5+
import kotlinx.coroutines.channels.produce
6+
import kotlinx.coroutines.coroutineScope
7+
import kotlinx.coroutines.delay
8+
import kotlinx.coroutines.flow.Flow
9+
import kotlinx.coroutines.flow.consumeAsFlow
10+
import kotlinx.coroutines.flow.flow
11+
import kotlinx.coroutines.launch
12+
13+
/**
14+
UseCase: We want to trigger some processing. While the downstream is currently
15+
busy, we want to drop the current trigger emission.
16+
17+
With a SharedFlow, this is not possible, since we need to define a buffer size of
18+
> 0 for buffer strategies like "DROP_LATEST". Channels however have a buffer sice of 0
19+
by default.
20+
21+
Another option is to use the custom operator "dropIfBusy" (see below)
22+
23+
See also: https://stackoverflow.com/questions/64844821/how-to-drop-latest-with-coroutine-flowt/74560222#74560222
24+
**/
25+
26+
fun <T> Flow<T>.dropIfBusy(): Flow<T> = flow {
27+
coroutineScope {
28+
val channel = produce {
29+
collect { trySend(it) }
30+
}
31+
channel.consumeEach { emit(it) }
32+
}
33+
}
34+
35+
suspend fun main(): Unit = coroutineScope {
36+
37+
val channel = Channel<Int>()
38+
39+
launch {
40+
channel
41+
.consumeAsFlow()
42+
.collect {
43+
println("Process $it")
44+
delay(1000)
45+
println("$it processed")
46+
}
47+
}
48+
49+
launch {
50+
51+
delay(100)
52+
53+
// 1 should be processed
54+
channel.trySend(1)
55+
println("sharedFlow emits 1")
56+
57+
// 2 should not be processed since downstream is busy
58+
channel.trySend(2)
59+
println("sharedFlow emits 2")
60+
61+
// 3 should be processed again
62+
delay(2000)
63+
channel.trySend(3)
64+
println("sharedFlow emits 3")
65+
}
66+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package com.lukaslechner.coroutineusecasesonandroid.playground.flow.concurrency
2+
3+
import kotlinx.coroutines.coroutineScope
4+
import kotlinx.coroutines.delay
5+
import kotlinx.coroutines.flow.MutableStateFlow
6+
import kotlinx.coroutines.launch
7+
import kotlin.system.measureTimeMillis
8+
9+
suspend fun main(): Unit = coroutineScope {
10+
11+
val flow = MutableStateFlow(0)
12+
13+
// Collector 1
14+
launch {
15+
flow.collect {
16+
println("Collector 1 processes $it")
17+
}
18+
}
19+
20+
// Collector 2
21+
launch {
22+
flow.collect {
23+
println("Collector 2 processes $it")
24+
delay(100)
25+
}
26+
}
27+
28+
// Emitter
29+
launch {
30+
val timeToEmit = measureTimeMillis {
31+
repeat(5) {
32+
flow.emit(it)
33+
delay(10)
34+
}
35+
}
36+
println("Time to emit all values: $timeToEmit ms")
37+
}
38+
}
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.concurrency
2+
3+
import kotlinx.coroutines.coroutineScope
4+
import kotlinx.coroutines.delay
5+
import kotlinx.coroutines.flow.buffer
6+
import kotlinx.coroutines.flow.flow
7+
8+
suspend fun main() = coroutineScope {
9+
10+
val flow = flow {
11+
repeat(5) {
12+
println("Emitter: Start Cooking Pancake $it")
13+
delay(100)
14+
println("Emitter: Pancake $it ready!")
15+
emit(it)
16+
}
17+
}.buffer()
18+
19+
flow.collect {
20+
println("Collector: Start eating pancake $it")
21+
delay(300)
22+
println("Collector: Finished eating pancake $it")
23+
}
24+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package com.lukaslechner.coroutineusecasesonandroid.playground.flow.concurrency
2+
3+
import kotlinx.coroutines.channels.BufferOverflow
4+
import kotlinx.coroutines.coroutineScope
5+
import kotlinx.coroutines.delay
6+
import kotlinx.coroutines.flow.buffer
7+
import kotlinx.coroutines.flow.flow
8+
9+
suspend fun main() = coroutineScope {
10+
11+
val flow = flow {
12+
repeat(5) {
13+
val pancakeIndex = it + 1
14+
println("Emitter: Start Cooking Pancake $pancakeIndex")
15+
delay(100)
16+
println("Emitter: Pancake $pancakeIndex ready!")
17+
emit(pancakeIndex)
18+
}
19+
}.buffer(capacity = 1, onBufferOverflow = BufferOverflow.SUSPEND)
20+
21+
flow.collect {
22+
println("Collector: Start eating pancake $it")
23+
delay(300)
24+
println("Collector: Finished eating pancake $it")
25+
}
26+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package com.lukaslechner.coroutineusecasesonandroid.playground.flow.concurrency
2+
3+
import kotlinx.coroutines.channels.BufferOverflow
4+
import kotlinx.coroutines.coroutineScope
5+
import kotlinx.coroutines.delay
6+
import kotlinx.coroutines.flow.buffer
7+
import kotlinx.coroutines.flow.flow
8+
9+
suspend fun main() = coroutineScope {
10+
11+
val flow = flow {
12+
repeat(5) {
13+
val pancakeIndex = it + 1
14+
println("Emitter: Start Cooking Pancake $pancakeIndex")
15+
delay(100)
16+
println("Emitter: Pancake $pancakeIndex ready!")
17+
emit(pancakeIndex)
18+
}
19+
}.buffer(capacity = 1, onBufferOverflow = BufferOverflow.DROP_OLDEST)
20+
21+
flow.collect {
22+
println("Collector: Start eating pancake $it")
23+
delay(300)
24+
println("Collector: Finished eating pancake $it")
25+
}
26+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package com.lukaslechner.coroutineusecasesonandroid.playground.flow.concurrency
2+
3+
import kotlinx.coroutines.channels.BufferOverflow
4+
import kotlinx.coroutines.coroutineScope
5+
import kotlinx.coroutines.delay
6+
import kotlinx.coroutines.flow.buffer
7+
import kotlinx.coroutines.flow.flow
8+
9+
suspend fun main() = coroutineScope {
10+
11+
val flow = flow {
12+
repeat(5) {
13+
val pancakeIndex = it + 1
14+
println("Emitter: Start Cooking Pancake $pancakeIndex")
15+
delay(100)
16+
println("Emitter: Pancake $pancakeIndex ready!")
17+
emit(pancakeIndex)
18+
}
19+
}.buffer(capacity = 1, onBufferOverflow = BufferOverflow.DROP_LATEST)
20+
21+
flow.collect {
22+
println("Collector: Start eating pancake $it")
23+
delay(300)
24+
println("Collector: Finished eating pancake $it")
25+
}
26+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package com.lukaslechner.coroutineusecasesonandroid.playground.flow.concurrency
2+
3+
import kotlinx.coroutines.channels.Channel.Factory.UNLIMITED
4+
import kotlinx.coroutines.coroutineScope
5+
import kotlinx.coroutines.delay
6+
import kotlinx.coroutines.flow.buffer
7+
import kotlinx.coroutines.flow.flow
8+
9+
suspend fun main() = coroutineScope {
10+
11+
val flow = flow {
12+
repeat(5) {
13+
val pancakeIndex = it + 1
14+
println("Emitter: Start Cooking Pancake $pancakeIndex")
15+
delay(100)
16+
println("Emitter: Pancake $pancakeIndex ready!")
17+
emit(pancakeIndex)
18+
}
19+
}.buffer(capacity = UNLIMITED)
20+
21+
flow.collect {
22+
println("Collector: Start eating pancake $it")
23+
delay(300)
24+
println("Collector: Finished eating pancake $it")
25+
}
26+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package com.lukaslechner.coroutineusecasesonandroid.playground.flow.concurrency
2+
3+
import kotlinx.coroutines.coroutineScope
4+
import kotlinx.coroutines.delay
5+
import kotlinx.coroutines.flow.collectLatest
6+
import kotlinx.coroutines.flow.flow
7+
8+
suspend fun main() = coroutineScope {
9+
10+
val flow = flow {
11+
repeat(5) {
12+
val pancakeIndex = it + 1
13+
println("Emitter: Start Cooking Pancake $pancakeIndex")
14+
delay(100)
15+
println("Emitter: Pancake $pancakeIndex ready!")
16+
emit(pancakeIndex)
17+
}
18+
}
19+
20+
flow.collectLatest {
21+
println("Collector: Start eating pancake $it")
22+
delay(300)
23+
println("Collector: Finished eating pancake $it")
24+
}
25+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package com.lukaslechner.coroutineusecasesonandroid.playground.flow.concurrency
2+
3+
import kotlinx.coroutines.coroutineScope
4+
import kotlinx.coroutines.delay
5+
import kotlinx.coroutines.flow.flow
6+
import kotlinx.coroutines.flow.mapLatest
7+
8+
suspend fun main() = coroutineScope {
9+
10+
val flow = flow {
11+
repeat(5) {
12+
val pancakeIndex = it + 1
13+
println("Emitter: Start Cooking Pancake $pancakeIndex")
14+
delay(100)
15+
println("Emitter: Pancake $pancakeIndex ready!")
16+
emit(pancakeIndex)
17+
}
18+
}.mapLatest {
19+
println("Add topping onto the pancake $it")
20+
delay(200)
21+
it
22+
}
23+
24+
flow.collect {
25+
println("Collector: Start eating pancake $it")
26+
delay(300)
27+
println("Collector: Finished eating pancake $it")
28+
}
29+
}
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.concurrency
2+
3+
import kotlinx.coroutines.coroutineScope
4+
import kotlinx.coroutines.delay
5+
import kotlinx.coroutines.flow.conflate
6+
import kotlinx.coroutines.flow.flow
7+
8+
suspend fun main() = coroutineScope {
9+
10+
val flow = flow {
11+
repeat(5) {
12+
println("Emitter: Start Cooking Pancake $it")
13+
delay(100)
14+
println("Emitter: Pancake $it ready!")
15+
emit(it)
16+
}
17+
}.conflate()
18+
19+
flow.collect {
20+
println("Collector: Start eating pancake $it")
21+
delay(300)
22+
println("Collector: Finished eating pancake $it")
23+
}
24+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package com.lukaslechner.coroutineusecasesonandroid.playground.flow.concurrency
2+
3+
import kotlinx.coroutines.coroutineScope
4+
import kotlinx.coroutines.delay
5+
import kotlinx.coroutines.flow.MutableSharedFlow
6+
import kotlinx.coroutines.launch
7+
import kotlin.system.measureTimeMillis
8+
9+
suspend fun main(): Unit = coroutineScope {
10+
11+
val flow = MutableSharedFlow<Int>(extraBufferCapacity = 10)
12+
13+
// Collector 1
14+
launch {
15+
flow.collect {
16+
println("Collector 1 processes $it")
17+
}
18+
}
19+
20+
// Collector 2
21+
launch {
22+
flow.collect {
23+
println("Collector 2 processes $it")
24+
delay(100)
25+
}
26+
}
27+
28+
// Emitter
29+
launch {
30+
val timeToEmit = measureTimeMillis {
31+
repeat(5) {
32+
flow.emit(it)
33+
delay(10)
34+
}
35+
}
36+
println("Time to emit all values: $timeToEmit ms")
37+
}
38+
}

app/src/main/res/values/strings.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<resources>
2-
<string name="app_name">Coroutine Usecases on Android</string>
2+
<string name="app_name">Coroutines and Flows on Android</string>
33
<string name="perform_single_network_request_on_background_thread">Load recent Android Versions</string>
44
<string name="perform_2_network_requests_sequentially">Load Features of most recent Android Version</string>
55
<string name="load_features_of_android_versions_sequentially">Load Features of Android Versions sequentially</string>

documentation/images/Logo-new.png

-337 KB
Loading

documentation/images/course.png

72.1 KB
Loading

0 commit comments

Comments
 (0)