background
- There is a StateFlow and its listeners
private val stateFlow = MutableStateFlow(kotlin.Pair<String, ArrayList<String>>("abc", ArrayList()))
Copy the code
GlobalScope.launch {
stateFlow.collect {
// do something}}Copy the code
- Update the ArrayList and try emit
GlobalScope.launch {
stateFlow.value.second.add("test")
stateFlow.emit(stateFlow.value)
}
Copy the code
Actually, collect is not called
why
The real implementer of MutableStateFlow is StateFlowImpl, and the emit method code is as follows:
override suspend fun emit(value: T) {
this.value = value
}
Copy the code
Look at the set method of value:
public override var value: T
get() = NULL.unbox(_state.value)
set(value) { updateState(null, value ? : NULL) }Copy the code
private fun updateState(expectedState: Any? , newState: Any): Boolean { var curSequence = 0 var curSlots: Array<StateFlowSlot? >? = this.slots // benign race, we will not use it synchronized(this) { val oldState = _state.value if (expectedState ! = null && oldState ! = expectedState) return false // CAS support if (oldState == newState) return true // Don't do anything if value is not changing, but CAS -> true _state.value = newState curSequence = sequence ... Omit some code}}Copy the code
If (oldState == newState) return true if (oldState == newState) return true if (oldState == newState) return true
Another question
Try the following code when emit:
GlobalScope.launch {
stateFlow.value.apply {
stateFlow.emit(kotlin.Pair(first, second))
}
}
Copy the code
In fact, the code above still doesn’t solve the problem because kotlin.Pair overwrites equals by default, checking kotlin.Pair decomcompiled Java files
public final class Pair {
public int hashCode(a) {
Object var10000 = this.first;
intvar1 = (var10000 ! =null ? var10000.hashCode() : 0) * 31;
Object var10001 = this.second;
returnvar1 + (var10001 ! =null ? var10001.hashCode() : 0);
}
public boolean equals(@Nullable Object var1) {
if (this! = var1) {if (var1 instanceof Te.Pair) {
Te.Pair var2 = (Te.Pair) var1;
if (Intrinsics.areEqual(this.first, var2.first) && Intrinsics.areEqual(this.second, var2.second)) {
return true; }}return false;
} else {
return true; }}}Copy the code
The Intrinsics. AreEqual code is as follows:
public static boolean areEqual(Object first, Object second) {
return first == null ? second == null : first.equals(second);
}
Copy the code
So the condition “if (oldState == newState) return true” is true because Kotlin overwrites equals by default and pair.first is the same as pair.second, even though the pair itself is different
The solution
Because the StateFlow source code cannot be modified and is scenario-specific, you cannot change the judgment condition to Kotlin’s “===”; Use Android.util. Pair or customize Java Pair class
conclusion
=== === === === === =