0

So I'm just getting back to Android development after being away from it for several years, and of course, it's vastly different now, what with Jetpack Compose being the hot new stuff now.

I'm kicking off a Kotlin coroutine that is a long process, but one that I can calculate its progress precisely. I want to show a LinearProgressIndicator in my @Composable view (the one that kicked off the coroutine), but I can't figure out the correct terms to search for to figure out how to pass the progress from the coroutine back into the @Composable view to update the progress indicator in real-time.

Edit/update: I'm going to try to re-phrase my question with code:

In my @Composable view, I'm kicking off a long-running, but measurable task:

@Composable
fun ConfigureFilesScreen() {
   var copyProgress by remember { mutableStateOf(0f) }
   var copyTotal by remember { mutableStateOf(0L) }
   var copyCompleted by remember { mutableStateOf (0L)}
   ...
   LinearProgressIndicator(progress = copyProgress)
   ...
   LaunchedEffect(key1 = true) {
       copyTotal = preflightFiles()
       failedReason = processFiles()
   }

copyProgress is calculated by copyCompleted / copyTotal; processFiles() knows how much processing has been done, which is the data with which I want to update the progress value of the LinearProgressIndicator view. It is defined thusly:

private suspend fun processFiles(): String? {
...
}

How do pass the variables/values between processFiles() (NOT a @Composable function) and ConfigureFilesScreen() (IS a @Composable function) such that the latter updates the progress value of the LinearProgressIndicator?

randallmeadows
  • 833
  • 1
  • 10
  • 19
  • Kindly provide a [minimal-reproducible-example](https://stackoverflow.com/help/minimal-reproducible-example) – Abhimanyu Jun 23 '23 at 05:19
  • 1
    LinearProgressBar has a parameter to indicate progress. Jetpack Compose is declarative, so you have to pass the progress from state holder to Composable using a parameter. – Abhimanyu Jun 23 '23 at 05:20
  • Yes, I know all of *this* information; I'm looking for more details on exactly *how* to implement that. As I posted, I've not been able to figure out the correct search terms that lead me to actual details. – randallmeadows Jun 24 '23 at 02:34
  • @Abhimanyu does my edit/update help? – randallmeadows Jun 24 '23 at 05:11
  • Is the `processFiles()` a method in ViewModel? Please share where it is declared. In most cases, this would be the approach, you expose observable data (Flow, RxJava, LiveData depending on the architecture you use) and collect/observe it in the Composable and update the UI accordingly. – Abhimanyu Jun 24 '23 at 05:50

2 Answers2

0
 LinearProgressIndicator(
   modifier = Modifier
               .fillMaxWidth(.72f)
               .height(5.dp)
               .clip(RoundedCornerShape(50)),
                backgroundColor = LocalCustomColorsPalette.current.linearProgressIndicatorColor,
    color = MajorelleBlue,
    progress = 45.toFloat() / 100)

In progress i will set my progress to 45 percent out of 100 and progress.

Hanif Shaikh
  • 500
  • 1
  • 10
0

Answering my own question, for posterity:

No ViewModel needed. In the @Composable where the LinearProgressIndicator lives, declare the progress tracker:

val copyProgress: MutableState<Float> = remember { mutableStateOf(0.0f) }

Set the progress of indicator using its .value:

LinearProgressIndicator(progress = copyProgress.value)

Declare the long-running process thusly:

private suspend fun updateDatabase(copyProgress: MutableState<Float>): String? {...}

and call it like so:

LaunchedEffect(key1 = true) {
    failedReason = updateDatabase(copyProgress)
}

and then simply update the .value as needed in the time-consuming method:

copyProgress.value = copiedSoFar.toFloat() / copyTotal.toFloat()

This gets called repeatedly and updates the progress display beautifully. (My granularity was small enough that I had no need to animate it, but presumably this could be added easily enough.)

randallmeadows
  • 833
  • 1
  • 10
  • 19