I'm stuck trying to understand how to get a variable initialised, and later updated, in kotlin to update in Jetpack Compose and cause a composition that uses it to recompose. The variable is an arraylist of bitmaps set up like so (all of this works fine so I have not included the getOutputDirectory() and imageReaderNew() functions):
// set up an empty bitmaps arraylist
// should I be using mutableListOf() here? if so how?
var bitmaps: ArrayList<Bitmap> = ArrayList()
// get the uri of the folder to save images to
val outputDirectory = getOutputDirectory()
// read in a list of images in the images folder
var fileList: ArrayList<File> = imageReaderNew(outputDirectory)
// get a list of bitmaps of the images
bitmaps = getBitmapList(fileList)
When I initialise my composition I do this:
BottomSheetScaffold(
scaffoldState = scaffoldState,
sheetPeekHeight = 0.dp,
sheetContent = {
PhotoBottomSheetContent(
bitmaps = bitmaps,
//should I be using remember here?
//bitmaps = remember { bitmaps },
modifier = Modifier.fillMaxWidth()
)
}
)
{ }
Finally, in my composable I do this:
fun PhotoBottomSheetContent(
bitmaps: List<Bitmap>,
// should I be using mutableListOf() or remember { } here? again if so how?
modifier: Modifier = Modifier
)
{
}
The way you're doing it doesn’t work because Jetpack Compose doesn’t automatically track changes to regular variables like ArrayList
. Compose only recomposes when it detects changes to state objects it’s explicitly observing (like mutableStateOf
or mutableStateListOf
). Since bitmaps
is just a plain ArrayList
, updating it won’t trigger recomposition.
To make Compose track changes to bitmaps
and trigger recomposition, you need to wrap it in a Compose state. Here’s how:
Use mutableStateListOf
to ensures Compose tracks changes to individual items (adding/removing items):
val bitmaps = remember { mutableStateListOf<Bitmap>() }
Use LaunchedEffect
to load bitmaps without blocking the UI. Update the state when the data is ready:
LaunchedEffect(Unit) {
val outputDirectory = getOutputDirectory()
val fileList = imageReaderNew(outputDirectory)
val loadedBitmaps = getBitmapList(fileList)
bitmaps.clear()
bitmaps.addAll(loadedBitmaps)
}
Pass the state to your composable. No need for remember
here—Compose will automatically observe the state:
BottomSheetScaffold(
sheetContent = {
PhotoBottomSheetContent(bitmaps = bitmaps)
}
)
In PhotoBottomSheetContent
, use the bitmaps
list as usual. It will automatically recompose when the state changes:
@Composable
fun PhotoBottomSheetContent(bitmaps: List<Bitmap>) {
// This will recompose when bitmaps changes
}
If you’re replacing the entire list (like loading a new set of bitmaps), you can use mutableStateOf
instead of mutableStateListOf
. It would look like
var bitmaps by remember { mutableStateOf<List<Bitmap>>(emptyList()) }
LaunchedEffect(Unit) {
val loadedBitmaps = getBitmapList(fileList)
bitmaps = loadedBitmaps // Reassign the entire list
}