Description
Hi there.
First, prehistory. I've published an app which I was working on to Google Play as alpha version and got strange crash reports in Crashlytics with StackOverflowError
. I'm not even sure that the problem is related to coroutines (it seems to be more related to ProGuard or R8 tools), but stacktraces include links to coroutines, so that's why I'm placing an issue here.
I created a simple repository as example to show the issue. It's simplified a lot, production app has much more complicated architecture and uses coroutines as base for domain layer.
Example has a simple view model, which has live data based on state:
private val _state = MutableLiveData(MainViewState())
val state: LiveData<MainViewState>
get() = _state
State is a data class:
data class MainViewState(val list: List<Int> = emptyList())
Activity observes this live data state:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
viewModel.state.observe(this, Observer(::renderViewState))
}
In the production app view model collects flow returned by Room
library in init
block. In the example repo I just created a simple flow:
init {
viewModelScope.launch {
flow {
val list = arrayListOf<Int>()
for (i in 0..100) {
list.add(Random(100).nextInt())
}
emit(list)
}.flowOn(Dispatchers.Default)
.distinctUntilChanged()
.collect { list ->
Log.e("Collect list", list.toString())
}
}
}
flowOn(Dispatchers.Default)
and distinctUntilChanged()
methods are placed here just to match the behavior of the actual app. Also I emulated release
mode by setting the following in build.gradle
:
debug {
debuggable false
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
And android.enableR8.fullMode=true
in gradle.properties
.
Actual issue is in that app crashes with these parameters, but everything works fine with another variations. I've got the following results. Crash doesn't appear if:
- Set
debuggable
totrue
- Using
proguard-android.txt
instead ofproguard-android-optimize.txt
- Removing
android.enableR8.fullMode=true
. Works for bothproguard-android.txt
andproguard-android-optimize.txt
- Removing
.flowOn(Dispatchers.Default)
from chain - Using the same dispatchers for
.flowOn()
andviewModelScope.launch()
Each item in the above list describes changing of single parameter without affecting the rest. Maybe I missed something or just misunderstood basic concepts, but it's interesting why stacktrace points to StackOverflowError
exception.
Deobfuscated stacktrace for example app is attached: stacktrace.txt.