view does not recompose on flow value change

Viewed 38

So I looked for a solution on StackOverflow and read the documentation to see if I was doing something wrong, but I could find out.

I have a list of activities that I fetch from Firestore and display in a LazyColumn. Every activity has a name of an image that I have to get its link from Firebase storage. After I get the link in my variable, I expect the view (AsyncImage) to recompose as the variable is of type StateFlow, but nothing happens.

In my repository file, the code for getting actitivities and the download URL of the image works fine.

In my viewModel, I have two functions to load the activities and the download URL:

viewModel((private val dataSource: ChadHubDigitDataSource): ViewModel() {
...
    var activities: LiveData<ActivityResponse>? = null
    private var _uri = MutableStateFlow<Uri>(Uri.parse(""))
    val uri: StateFlow<Uri>
        get() = _uri

    fun loadActivities() {
        activities = flow {
                emit(dataSource.getActivities())
            }.stateIn(
            scope = viewModelScope,
            started = SharingStarted.WhileSubscribed(5000),
            initialValue = ActivityResponse()
        )
    }

    fun loadImage(imageName: String) {
            _uri.value = dataSource.getImage(imageName)
    }

Bellow is the code in my compose function:

val activities = _eventsViewModel.activities?.collectAsState()?.value?.activity
LazyColumn {
    if (activities != null)
    {
        items(activities) { item ->
            Column(
                ...
            ) {
                // Loading the URL of the image
                _eventsViewModel.loadImage(item.img)
                Image(
                    ...
                    painter = rememberAsyncImagePainter(
                            ImageRequest.Builder(
                                LocalContext.current
                            )
                                .data(
                                data = _eventsViewModel.uri.collectAsState().value
                            )
                                .apply(
                                    block = fun ImageRequest.Builder.() {
                                        crossfade(false)
                                        placeholder(R.drawable.placeholder)
                                        error(R.drawable.placeholder)
                                    }
                                ).build()
                        ),
                    ...
                )
                ...
    }

When the activities are displayed, it's the error image that is displayed even after the value of the variable uri changed in the viewModel.

Do you know a better way I can do such functionality or why my code is not working?

1 Answers

I tried your ImageRequest.Builder block of code, my Firebase Image fetching implementation stopped working, only showing the placeholder and not fetching.

 ImageRequest.Builder(context)
            .data(url)
            .apply (
                block = fun ImageRequest.Builder.() {
                    crossfade(false)
                    placeholder(R.drawable.placeholder)
                    error(R.drawable.placeholder)
                }
            )
            .build()

Can you try doing it this way?

   ImageRequest.Builder(context)
            .data(url)
            .crossfade(false)
            .placeholder(R.drawable.placeholder)
            .error(R.drawable.placeholder)
            .build()
Related