Home > Software design >  Will the App crash when LaunchedEffect(Unit){ while (true) {...} } is launched again and again in Je
Will the App crash when LaunchedEffect(Unit){ while (true) {...} } is launched again and again in Je

Time:07-30

The following sample code is from a website, the function of the code is to display a clock. The author use the code LaunchedEffect(Unit) { while (true) {... delay(1000)} } to recomposition UI every second just like a clock.

A: Will the code LaunchedEffect(Unit){ while (true) {...} } generate many coroutines? will it cause the App crash?

B: Will the variable such as val second = remember{...} be locked when many coroutines try to assign new value to it?

class ClockActivity : ComponentActivity() {
    
    override fun onCreate(savedInstanceState: Bundle?) {
    
        super.onCreate(savedInstanceState)
        setContent {
    
            Column(modifier = Modifier.fillMaxSize()) {
    
                Box(
                    contentAlignment = Alignment.Center,
                    modifier = Modifier
                        .fillMaxWidth()
                        .fillMaxHeight(0.5f)
                ) {    
                    Clock()
                }                
            }
        }
    }
}


 @Composable
 fun Clock() {
    
        val hour = remember { mutableStateOf(0f) }
        val minute = remember { mutableStateOf(0f)  }
        val second = remember {  mutableStateOf(0f)  }

        LaunchedEffect(Unit) {    
            while (true) {
    
                val cal = Calendar.getInstance()
                hour.value = cal.get(Calendar.HOUR).toFloat()
                minute.value = cal.get(Calendar.MINUTE).toFloat()
                second.value = cal.get(Calendar.SECOND).toFloat()
                delay(1000)
            }
        }

        val diameter = 200.dp
        val color1 = Color.Black

        Canvas(
            modifier = Modifier
                .size(diameter, diameter)
        ) {
    
            val outCircleR = size.width / 2
            val innerCircleR = (size.width / 2 * 0.8).toFloat()
            
            drawCircle(color = color1, radius = size.width * 0.02f)
           
            drawCircle(color = color1, radius = outCircleR, style = Stroke(4f))
           
            drawCircle(
                color = color1,
                radius = innerCircleR,
                style = Stroke(2f)
            )

            translate(size.width / 2, size.height / 2) {                 
               ...
                val secondLength = outCircleR * 0.9f
                val secondAngle = second.value.div(60) * 360
                drawLine(
                    color = color1,
                    start = Offset.Zero,
                    end = Offset(
                        (secondLength * cos(secondAngle * Math.PI / 180)).toFloat(),
                        (secondLength * sin(secondAngle * Math.PI / 180)).toFloat()
                    ),
                    strokeWidth = 2f,
                    cap = StrokeCap.Round
                )
               ...
            }
        }
    }
}

CodePudding user response:

A: Will the code LaunchedEffect(Unit){ while (true) {...} } generate many coroutines? will it cause the App crash?

No, it won't create many coroutines. A single LaunchedEffect launches a single coroutine and:

  1. cancels it and re-launches a coroutine when any of LaunchedEffect key parameters change.
  2. cancels it when LaunchedEffect leaves the composition

Since in your code example the key parameter is set to Unit it never changes, so case 1. will never happen in your case. There will be only one coroutine started by LaunchedEffect and it will run until the composable is part of the composition.

Additionally the code inside the coroutine will only be run once per second. Between re-runs the coroutine will be suspended.

B: Will the variable such as val second = remember{...} be locked when many coroutines try to assign new value to it?

Since in your case only one coroutine assigns a new value to it you don't have to worry about this.

I don't know how MutableState works when there are multiple coroutines accessing it, but assigning a new value should not be problematic even if there are multiple coroutines doing it at the same time, so you would not need synchronization for that. The synchronization becomes important if you would have more than one coroutine manipulating the value in such a way, where another coroutine running in between that manipulation, would leave the value in an invalid state.

  • Related