background

  1. 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
  1. 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

=== === === === === =