Search code examples
androidandroid-jetpack-composeandroid-jetpack

How do I observe when a list stored in another class changes to update my Compose UI?


I'm new to Compose and Android, so I may use some incorrect terminology here, but I'm basically trying to observe when a list is changed and update my UI accordingly. The list is immutable so I just want to observe when the reference changes to a new list.

class MyDataHolder {
    val myData = mutableStateOf(emptyList<MyData>())
}

myData is the list I wish to observe and is being initialized with an empty list.

In my composable, I create an instance of MyDataHolder and (attempt to) observe changes to its myData property.

@Composable
fun MainScreen() {
    val dataHolder = MyDataHolder()
    val myData by remember { dataHolder.myData }

    Box(Modifier.fillMaxSize()) {
        MyOtherScreen(dataHolder)
        Box {
            myData.forEach{
                Box(modifier = Modifier.size(60.dp, 60.dp)) {
                    
                }
            }
        }
    }
}

dataHolder is passed to MyOtherScreen which passes dataHolder to a subclass of ImageAnalysis.Analyzer which updates the myData list continuously.

The problem I am seeing is that even when the myData list in dataHolder is updated to a non-empty list, the UI never contains any of the Box items that should be displayed for each item in the myData list (I have verified this in the Layout Inspector).

What am I be doing wrong here?


Solution

  • You want to use a Flow to observe in your compose function

    Something like

    class MyDataHolder {
        private val myData = mutableStateOf(emptyList<MyData>())
        private val _mutableMyDataStateFlow: MutableStateFlow<List<MyData>> = MutableStateFlow(mutableListOf())
        val myDataStateFlow: StateFlow<List<MyData>> = _mutableMyDataStateFlow.asStateFlow()
    
        fun updateData(newData: List<MyData>){
            myData = newData
            _mutableMyDataStateFlow.emit(myData)
        }
        
    }
    

    Then in your composable you listen for changes

    @Composable
    fun MyComposableList(myDataHolder: MyDataHolder){
        val myData = myDataHolder.myDataStateFlow.collectAsStateWithLifecycle()
        
        //Update your list with myData
    }
    

    Anytime you emit new data your compose function will update and myData will have the new data so just update your list with myData