error: @Composable invocations can only happen from the context of a @Composable function

4.5k Views Asked by At

would like to start TimerView() in onClick - TimerView is a text composable but the above mentioned error appears - both are marked composables

Composable
fun LosB(BLY: String, YArray: ArrayList<String> /* = java.util.ArrayList<kotlin.String> */) {
    //  val Tit = mutableStateOf("sdfsdf")
    val context = LocalContext.current
    Column(
        horizontalAlignment = Alignment.CenterHorizontally,
        modifier = Modifier.fillMaxWidth()
    ) {


        OutlinedButton(
            onClick = { TimerView()},
            shape = CircleShape,
            border = BorderStroke(1.dp, Color(0xFFADFF2F)),
            colors = ButtonDefaults.buttonColors(
                backgroundColor = Color(0xFF1C536F),
                contentColor = Color.White
            )
        ) {


            Text(text = "OK", fontSize = 20.sp)

        }
    }

Any help? want to show a txt counter -

2

There are 2 best solutions below

0
ioanntza22 On

You need just make a mutableState like this

var timeViewState by remember {
    mutableStateOf(false)
}

if(timeViewState) {
   TimerView()
}

OutlinedButton(
   onClick = { timeViewState = true },
...

Home I help you

1
Steyrix On

I will come with a little explanation. Composable functions are run in parallel, that means that Compose take care of internal thread pool to perform fast and optimized composition.

However, onClick takes place on UI thread, which is out of composition context and is not controlled by the thread pool, that is the reason why you cannot call composable function from onClick.

To perform such operation you indeed need to create a mutable state which will be controlled by the button.

var isTimerVisible by remember {
    mutableStateOf(false)
}

if (isTimerVisible) {
    TimerView()
}

OutlinedButton(
        onClick = { isTimerVisible = !isTimerVisible },
        shape = CircleShape,
        border = BorderStroke(1.dp, Color(0xFFADFF2F)),
        colors = ButtonDefaults.buttonColors(
            backgroundColor = Color(0xFF1C536F),
            contentColor = Color.White
        )
) {
        Text(text = "OK", fontSize = 20.sp)
}

UPD: With the help from z.g.y I understood that I was not quite correct about it.

@Compose annotation works similar as a suspend keyword in Kotlin, it is changing the functions' type. Composable function type is just like suspend is not compatible with regular function type.

Compiler treats that type of function differently, it inserts $composer parameter to it and call its' start method with a generated integer key.

fun TimerView($composer: Composer) {
    $composer.start(123) 
}

This composer object is passed to composable from parent composable, but since onClick is not composable and happens outside of composition context, there is no valid composer in it. So you cannot call composable without the composer

Compose, compose, compose...

Good article to read about it is here