Kotlin MutableStateFlow.collect is dropping values

♀尐吖头ヾ 提交于 2021-01-05 07:08:51

问题


I have an android app in which I'm trying to use coroutine flows to replace the existing Otto EventBus using my own event bus library. I'm seeing dropped values when setting the MutableStateFlow's value and then collecting in my app's code. I've created a much simpler project that demonstrates the same issue. Any thoughts on why values are being dropped from the MutableStateFlow?

Project's build.gradle

buildscript {
    ext.kotlin_version = "1.4.10"
    repositories {
        google()
        jcenter()
    }
    dependencies {
        classpath "com.android.tools.build:gradle:4.0.1"
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
        classpath 'com.google.gms:google-services:4.3.3'
        classpath 'com.google.firebase:firebase-crashlytics-gradle:2.3.0'
        classpath 'com.google.firebase:perf-plugin:1.3.1'

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects {
    repositories {
        google()
        jcenter()
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}

App Module's build.gradle

apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'com.google.gms.google-services'
apply plugin: 'com.google.firebase.crashlytics'
apply plugin: 'com.google.firebase.firebase-perf'

android {
    compileSdkVersion 29
    buildToolsVersion "29.0.3"

    defaultConfig {
        applicationId "com.cren90.sandbox"
        minSdkVersion 23
        targetSdkVersion 29
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    implementation fileTree(dir: "libs", include: ["*.jar"])
    implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
    implementation 'androidx.core:core-ktx:1.3.1'
    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.7'

    implementation 'androidx.appcompat:appcompat:1.2.0'
    implementation 'androidx.fragment:fragment:1.2.5'
    implementation 'androidx.fragment:fragment-ktx:1.2.5'
    implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.2.0'
    implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.2.0'
    implementation 'androidx.lifecycle:lifecycle-viewmodel:2.2.0'
    implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
    implementation 'androidx.constraintlayout:constraintlayout:2.0.1'
    implementation 'com.google.firebase:firebase-analytics:17.5.0'
    implementation 'com.google.firebase:firebase-crashlytics:17.2.1'
    implementation 'com.google.firebase:firebase-perf:19.0.8'
    implementation 'com.google.firebase:firebase-messaging:20.2.4'
    implementation 'com.jakewharton.timber:timber:4.7.1'
    implementation 'androidx.legacy:legacy-support-v4:1.0.0'
    implementation 'androidx.navigation:navigation-runtime:2.3.0'
    implementation 'androidx.navigation:navigation-fragment:2.3.0'
    implementation 'androidx.navigation:navigation-ui:2.3.0'
    implementation 'androidx.navigation:navigation-runtime-ktx:2.3.0'
    implementation 'androidx.navigation:navigation-fragment-ktx:2.3.0'
    implementation 'androidx.navigation:navigation-ui-ktx:2.3.0'

    testImplementation 'junit:junit:4.13'
    androidTestImplementation 'androidx.test.ext:junit:1.1.2'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'

}

MainActivity.kt

package com.cren90.sandbox

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.navigation.findNavController
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
import timber.log.Timber
import java.lang.RuntimeException

class MainActivity : AppCompatActivity() {

    val flow: MutableStateFlow<Int> = MutableStateFlow<Int>(0)

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)



        CoroutineScope(Dispatchers.IO).launch {
            flow.collect {
                Timber.d("cren90 - $it")
            }
        }
    }

    override fun onStart() {
        super.onStart()
        (application as SandboxApplication).apply {
            startupTrace.putAttribute("APP_UUID", uuid)
            startupTrace.stop()
        }

    }

    override fun onResume() {
        super.onResume()


        for(i in 0..100) {
            flow.value = i
        }
    }
}

I'd expect this to log

2020-09-30 18:10:02.826 10533-10611/com.cren90.sandbox D/MainActivity$onCreate$1$invokeSuspend$$inlined$collect: cren90 - 0
2020-09-30 18:10:02.826 10533-10611/com.cren90.sandbox D/MainActivity$onCreate$1$invokeSuspend$$inlined$collect: cren90 - 1
2020-09-30 18:10:02.826 10533-10611/com.cren90.sandbox D/MainActivity$onCreate$1$invokeSuspend$$inlined$collect: cren90 - 2
...
2020-09-30 18:10:02.826 10533-10611/com.cren90.sandbox D/MainActivity$onCreate$1$invokeSuspend$$inlined$collect: cren90 - 98
2020-09-30 18:10:02.826 10533-10611/com.cren90.sandbox D/MainActivity$onCreate$1$invokeSuspend$$inlined$collect: cren90 - 99
2020-09-30 18:10:02.826 10533-10611/com.cren90.sandbox D/MainActivity$onCreate$1$invokeSuspend$$inlined$collect: cren90 - 100

but instead it logs

2020-09-30 18:10:02.826 10533-10611/com.cren90.sandbox D/MainActivity$onCreate$1$invokeSuspend$$inlined$collect: cren90 - 0
//Maybe 1 or 2 other random values in the 0-100 range
2020-09-30 18:10:02.826 10533-10611/com.cren90.sandbox D/MainActivity$onCreate$1$invokeSuspend$$inlined$collect: cren90 - 100

回答1:


StateFlow official documentation states:

The value of mutable state flow can be updated by setting its value property. Updates to the value are always conflated. So a slow collector skips fast updates, but always collects the most recently emitted value.

You can find StateFlow official documentation here.



来源:https://stackoverflow.com/questions/64147848/kotlin-mutablestateflow-collect-is-dropping-values

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!