Start with the kotlin flow
Abhishesh Srivastava
abhishesh_sri
Slide 2
Slide 2 text
● Threads
● Coroutines
Slide 3
Slide 3 text
fun doLongRunningWork(
callback: (x: Int) -> Unit) {
thread {
val result = compute()
callback(result)
}
}
Slide 4
Slide 4 text
suspend fun doLongRunningWork : Int() {
val result = compute()
return result
}
suspend fun compute() : Int {
...
}
Slide 5
Slide 5 text
fun doLongRunningWork(
callback: (x: Int) -> Unit) {
thread {
val result = compute()
callback(result)
}
}
suspend fun doLongRunningWork : Int() {
val result = compute()
return result
}
suspend fun compute() : Int {
...
}
Slide 6
Slide 6 text
doLongRunningWork {
doLongRunningWork {
...
...
}
}
couroutineScope.launch {
val first = doLongRunningWork()
val second = doLongRunningWork()
...
...
}
Slide 7
Slide 7 text
doLongRunningWork {
doLongRunningWork {
doLongRunningWork {
...
...
}
}
}
couroutineScope.launch {
val first = doLongRunningWork()
val second = doLongRunningWork()
val third = doLongRunningWork()
...
...
}
● Asynchronous data stream
● Built on top of coroutine
● Emits value
● Completes normally OR with exception
● Usually flows are cold
Slide 10
Slide 10 text
No content
Slide 11
Slide 11 text
● Asynchronous data stream
● Built on top of coroutine
● Emits value
● Completes normally OR with
exception
● Usually flows are cold
flow {
for (i in 1..10) {
emit(i)
}
}
Slide 12
Slide 12 text
● Asynchronous data stream
● Built on top of coroutine
● Emits value
● Completes normally OR with
exception
● Usually flows are cold
flow {
for (i in 1..10) {
println(“emit: $i”)
emit(i)
}
}
Slide 13
Slide 13 text
● Asynchronous data stream
● Built on top of coroutine
● Emits value
● Completes normally OR with
exception
● Usually flows are cold
flow {
for (i in 1..10) {
println(“emit: $i”)
emit(i)
}
}.collect {
println(“col: $it”)
println(it)
}
Slide 14
Slide 14 text
public interface Flow {
public suspend fun collect(collector: FlowCollector)
}
public interface FlowCollector {
public suspend fun emit(value: T)
}
CoroutineScope(Dispatchers.Main).launch {
flow {
withContext(Dispatchers.IO) {
for (i in 1..10) {
emit(i)
}
}
}.collect {
println(it)
}
}
Slide 27
Slide 27 text
CoroutineScope(Dispatchers.Main).launch {
flow {
withContext(Dispatchers.IO) {
for (i in 1..10) {
emit(i)
}
}
}.collect {
println(it)
}
}
java.lang.IllegalStateException: Flow
invariant is violated:
Slide 28
Slide 28 text
CoroutineScope(Dispatchers.Main).launch {
flow {
for (i in 1..10) {
emit(i)
}
}.flowOn(Dispatchers.IO)
.collect {
println(it)
}
}
Changes the context of upstream
flow
uiScope.launch {
dataFlow()
.catch{ e -> println(“caught $e“}
.collect { value ->
println(value)
}
}
a downstream exception must always be propagated to the
collector.
Slide 31
Slide 31 text
Retrofit supports suspend function
Integrated into many jetpack libraries
Other reactive libraries can be easily migrated to Flow
Slide 32
Slide 32 text
Integrated with room
@Dao
abstract class Dao {
@Query("SELECT * FROM table")
abstract fun getExamples(): Flow>
}
Slide 33
Slide 33 text
Integrated with live data
implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version"
fun LiveData.asFlow(): Flow {}
fun Flow.asLiveData(
context: CoroutineContext = EmptyCoroutineContext,
timeout: Duration
): LiveData { }
Slide 34
Slide 34 text
● Producer
● consumer
Slide 35
Slide 35 text
class FakeFlowProducer : FlowProducer {
fun data() = flow {
emit(ITEM_1)
}
fun allData() = listOf(ALL_VALUES).asFlow()
}
@Test
fun fakeFlowProducerTest() = runBlocking {
val producer = FakeFlowProducer()
val firstItem = producer.data.first()
assertThat(firstItem, isEqualTo(ITEM_1)
}
Slide 36
Slide 36 text
class FakeFlowProducer : FlowProducer {
fun data() = flow {
emit(ITEM_1)
}
fun allData() = listOf(ALL_VALUES).asFlow()
}
@Test
fun fakeFlowProducerTest() = runBlocking {
val producer = FakeFlowProducer()
val firstItem = producer.data.first()
assertThat(firstItem, isEqualTo(ITEM_1)
}
Creates a testcoroutinescope which have aa
testcoroutinedispatcher &
testcoroutineexceptionhandler. Also accepts and
lambda test body.
Slide 37
Slide 37 text
@Test
fun testMultipleValues() = runBlocking {
val producer = FakeFlowProducer()
val multipleValues = producer.multipleValues().toList()
assertThat(multipleValues, isEqualTo(ALL_VALUES))
}