Problem, Recomposition is not happening when i change UI State (2d LIST) in android jetpack compose

656 Views Asked by At

My problem is that i change the uiState but the effect is not there

class BoardViewModel : ViewModel() {
    private var board = mutableListOf<MutableList<Piece?>>()
    private val _uiState = MutableStateFlow(BoardUiState(board.toList()))
    val uiState: StateFlow<BoardUiState> = _uiState.asStateFlow()
    private var selectedPos: Pair<Int, Int>? = null

    init{
        reset()
    }

    private fun reset(){
        board = mutableListOf()
        // this that are not required 
        _uiState.value = BoardUiState(board)
    }

    fun onCellClicked(r: Int, c: Int){
        if(selectedPos != null) {
            move(selectedPos!!.first, selectedPos!!.second, r, c) // i verified this is executed
            selectedPos = null
        }
        else if(board[r][c] != null){
            selectedPos = r to c
        }
    }

    private fun move(sr: Int, sc: Int, dr: Int, dc: Int){
        val temp = board[sr][sc]
        board[sr][sc] = null
        board[dr][dc] = temp
        _uiState.update { currentState ->
            currentState.copy(board = board.toList()) // here im updating the state

             // PROBLEM HERE EVEN WHEN THE BOARD IS CHANGED THE EFFECT IS NOT THERE ON COMPOSITION
        }
    }
}

I verified that the problem is not in other parts of the program, i added dummy int variable to state and changed it in the move function, this time the change happened.

The problem is that change to board is not being detected.

Thanks in advance!

2

There are 2 best solutions below

1
Aiden On BEST ANSWER

MutableStateFlow uses structural equality comparison == whenever you update it's value (same goes for mutableStateOf by default), the update will never happen as the structure of the new list is the same as the old (mutated) one, the toList extension function will create a new list with the same elements.

docs:

https://kotlinlang.org/docs/equality.html

https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-state-flow/

0
tasjapr On

This happens because method toList() does not creates new object.

Replace this:

currentState.copy(board = board.toList())

Rith this:

currentState.copy(board = listOf(board))

Here is small sample in kotlin playground. You can run this code snippet and you will see, that the result is different for methods toList() and listOf()