Hi guys! I think that I'm having a race condition ...
# compose
t
Hi guys! I think that I'm having a race condition here with
ModalBottomSheetLayout
. Code in 🧵
Copy code
@ExperimentalMaterialApi
@Composable
@Preview
fun Test() {
    val scope = rememberCoroutineScope()
    val sheetState = rememberModalBottomSheetState(ModalBottomSheetValue.Hidden)
    var testVar by rememberSaveable { mutableStateOf(true)}
    val openSheet: (Boolean) -> Unit = {
        scope.launch {
            testVar = it
            sheetState.show()
            Log.i("test", "test")
        }
    }
    ModalBottomSheetLayout(
        sheetState = sheetState,
        sheetContent = {
            Box(
                modifier = Modifier
                    .padding(top = 12.dp)
                    .requiredSize(50.dp, 4.dp)
                    .clip(RoundedCornerShape(2.dp))
                    .background(DarkGray)
                    .align(alignment = Alignment.CenterHorizontally)
            )
            if (testVar) {
                TestModal1()
            } else
                TestModal2()
        },
        sheetShape = RoundedCornerShape(topStart = 18.dp, topEnd = 18.dp),
    ) {
        Row() {
            Button(onClick = {
                openSheet(true)
            }) {
                Text(text = "open sheet")
            }
            Button(onClick = {
                openSheet(false)
            }) {
                Text(text = "open sheet2")
            }
        }
    }
}

@Composable
@Preview
fun TestModal2() {
    Column(
        modifier = Modifier
            .padding(start = 28.dp, end = 28.dp, top = 10.dp, bottom = 28.dp)
            .fillMaxWidth(),
    ) {
        Row(
            verticalAlignment = Alignment.CenterVertically
        ) {
            Image(
                modifier = Modifier.padding(end = 8.dp),
                painter = painterResource(id = R.drawable.ic_full_swing_lesson),
                contentDescription = ""
            )
            Text(text = "TITLE 2", style = Roboto17W700)
        }
        ModalOption("Option 2")
        Spacer(modifier = Modifier.padding(8.dp))
        ModalOption("Option 2")

    }
}

@Composable
@Preview
fun TestModal1() {
    Column(
        modifier = Modifier
            .padding(start = 28.dp, end = 28.dp, top = 10.dp, bottom = 28.dp)
            .fillMaxWidth(),
    ) {
        Row(
            verticalAlignment = Alignment.CenterVertically
        ) {
            Image(
                modifier = Modifier.padding(end = 8.dp),
                painter = painterResource(id = R.drawable.ic_full_swing_lesson),
                contentDescription = ""
            )
            Text(text = "TITLE 1", style = Roboto17W700)
        }
        ModalOption("Option 1")
        Spacer(modifier = Modifier.padding(8.dp))
        ModalOption("Option 1")

    }
}

@Composable
fun ModalOption(text: String, onClick: () -> Unit = {}) {
    Card(
        modifier = Modifier.fillMaxWidth(),
        elevation = 8.dp,
        shape = Rounded8dpShape,
        backgroundColor = Color.White
    ) {
        Box(
            modifier = Modifier.clickable {
                onClick
            },
            contentAlignment = Alignment.CenterStart
        ) {
            Row(
                modifier = Modifier
                    .padding(14.dp)
                    .fillMaxWidth(),
                horizontalArrangement = Arrangement.SpaceBetween,
                verticalAlignment = Alignment.CenterVertically
            ) {
                Text(
                    modifier = Modifier.fillMaxWidth(.95f),
                    text = text
                )
                Image(
                    painter = painterResource(id = R.drawable.ic_orange_arrow_right),
                    contentDescription = ""
                )
            }
        }
    }
}
So here is just a layout that have 2 button and when u click it it will show a
ModalBottomSheet
But if the layout is complex enough when changing the state of the
testVar
it will trigger a recompose and when that recompose finish after the I call the
sheetState.show()
method it just do nothing
The log wont show up and the modal wont show either. If I press the button again it worked as it should.
But when I add
delay(150)
before calling the
sheetState.show()
method to make sure the recompose has finish. It worked fine
It's harder to reproduce this on faster machine
r
Copy code
class BottomSheetController constructor(private val scope: CoroutineScope) {

    private var job: Job? = null

    @OptIn(ExperimentalMaterialApi::class)
    fun showBottomSheet(
        sheetState: ModalBottomSheetState,
        block: () -> Unit,
    ) {
        job?.cancel()
        job = scope.launch {
            block()
            delay(200)
            sheetState.show()
        }
    }
}
I've faced similar situation, solved by canceling old job and adding delay of
200
ms
Copy code
val bottomController by remember { BottomSheetController(scope) }
bottomController.showBottomSheet(sheetState) {
                   //any init stuff
                }
t
I just add a delay and it worked but don't you think this shouldn't be happening?
These kind of issues will be so hard to figure out on production
r
t
I just had the same debugging journey as OP in the thread 😄