Hey, all, I have a question WRT viewmodels and cor...
# android
d
Hey, all, I have a question WRT viewmodels and coroutines. I'm calling a suspend function to download and show progress while the download occurs. But, the code is only firing the progress updates after the download has completed.
The download is called with the following:
Copy code
coroutineScope.launch(<http://Dispatchers.IO|Dispatchers.IO>) {
  comicBookViewModel.download(server, serverLink)
}
The download() method is:
Copy code
fun download(server: Server, serverLink: ServerLink) {
        viewModelScope.launch(<http://Dispatchers.IO|Dispatchers.IO>) {
            <http://Log.info|Log.info>(TAG, "Downloading ${serverLink.downloadLink} => ${serverLink.filename}")
            doAddDownload(serverLink.downloadLink)
            downloadFile(
                server,
                serverLink.downloadLink,
                "${libraryDirectory.value}/${serverLink.filename}",
                onProgress = { current, total ->
                    Log.debug(
                        TAG,
                        "Downloaded ${current} of ${total} for ${serverLink.downloadLink}"
                    )
                    doUpdateDownload(serverLink.downloadLink, current, total)
                })
            doRemoveDownload(serverLink.downloadLink)
        }
    }
And the method to update the view model state is:
Copy code
private fun doUpdateDownload(downloadLink: String, current: Long, total: Long) {
        val currentDownloads = _currentDownloads.value
        val entry = currentDownloads.first { it.downloadLink == downloadLink }
        currentDownloads.remove(entry)
        if (total > 0) {
            entry.progress = ((current / total).toFloat())
        } else {
            entry.progress = 0.0f
        }
        currentDownloads.add(entry)
        _currentDownloads.tryEmit(currentDownloads)
    }
I'm using com.rickclephas.kmp.observableviewmodel.MutableStateFlow for the state flow since it's a KMP project, and the other uses for it work correctly, but the progress updates never happen. Any ideas or suggestions?
c
you are emitting the same list again, so no โ€œstateโ€ change is triggers. you need to create a new list before each
tryEmit
โ˜๏ธ 1
d
@Chrimaeon Even if it's pulling out the entry, modifying it, and reinserting it? Should it create a new entry object for the list?
c
the reference is still the same
๐Ÿ‘ 1
d
Gotcha. I'll try that.
d
Creating a new object for the list didn't work: it's behaving the same as before. ๐Ÿ˜•
๐Ÿคท๐Ÿผ 1
c
why do you use a third party stateflow? the one on coroutines is multiplatform. https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-mutable-state-flow/
d
It is? I wasn't aware that it was KMP compatible.
c
the i.e
Common
in the upper right corner indicates the platform a class is available on
d
I had used it since it was a part of the tutorial I followed to setup the KMP ViewModel using the one from rickclephas.
Sadly, swapping out the MutableStateFlow didn't change things. ๐Ÿ˜•
c
you can try
update
lambda instead of
tryemit
๐Ÿ‘ 1
d
The issue may even more subtle than that: it looks like the code to calculate the progress never seems to get a value other than 0.0f. So I'm guessing that's why it never updates even when the entry is recreated.
๐Ÿ˜… 1
The code:
Copy code
val progress = when (total) {
            0L -> 0.0f
            else -> (current / total).toFloat()
        }
        Log.debug(TAG, "Progress was calculated to ${progress} from ${current} and ${total}")
is always producing this log output:
Copy code
2025-04-17 11:00:00.457  7167-7246  ComicBookViewModel      org.comixedproject.variant.android   D  Progress was calculated to 0.0 from 816453 and 9944836
The value is displayed using a LinearProgressBar which expects a value in the range (0..1)
Which leads me to realize I should be converting them to floats before the calculation.
c
d
Don't let the fact that I've been programming for a living for 30 years fool you: I still make the occasional silly mistake...
c
Been there, done that ๐Ÿ‘๐Ÿผ
d
It works! Thank you again!
๐Ÿ™Œ๐Ÿผ 1