Search code examples
androidkotlintextdialogandroid-jetpack-compose

Jetpack Compose AlertDialog Error: "@Composable invocations can only happen from the context of a @Composable function"


There appear to be an infinite number of explanations for this error on stackoverflow, none of which address my issue.

I am building a compose alert dialog. I am trying to show a list of options that can change depending on the data.

Dialog

@Composable
fun OptionSelectComposeDialog(
   vm: OptionSelectDialogViewModel
){
...
val optionList = vm.optionList
Column {
    if (openDialog.value) {
        AlertDialog(
            ...
            text = {
                OptionListDialogContent(optionList)
            },
            ...
        )
    }
}

In the OptionListDialogContent composable function I'm trying to print out the list, but the Text composable is giving an error.

OptionListDialogContent

@Composable
fun OptionListDialogContent(optionList: OptionList?) {

    val optionItemArray = optionList?.getOptionItemArray(null)

    LazyColumn() {
        if (optionItemArray != null) {
            optionItemArray.forEach { optionItem ->
                Text(text = optionItem.toString()) // Error "@Composable invocations can only happen from the context of a @Composable function"
            }
        }
    }
}

I suspected that the toString call on the optionItem is throwing this error, so I tried mapping the array to convert the array values to strings and still received this error.

OptionListDialogContent After converting the array to strings:

@Composable
fun OptionListDialogContent(optionList: OptionList?) {

    val optionItemArray = optionList?.getOptionItemArray(null)
    val optionItemStringArray = optionItemArray?.map { it.toString()}?.toTypedArray()

    LazyColumn() {
        if (optionItemStringArray != null) {
            optionItemStringArray.forEach { optionItem ->
                Timber.d("This is working? - optionItemArray.size: %s", optionItemArray.size)
                Text(text = optionItem) // Error "@Composable invocations can only happen from the context of a @Composable function"
            }
        }
    }
}

Anyone see where the issue is? (I have verified that optionItemArray is not null)


Solution

  • Turns out it is an issue with how I was using LazyColumn. LazyColumn needs to receive an array size. There are different ways to do this, but this is how I did it:

    LazyColumn() {
        if (optionItemStringArray != null) {
            items(optionItemStringArray.size) { i ->
                Row() {
                    Text(text = optionItemStringArray[i])
                }
            }
        }
    }