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
)
{
}
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
)
{
}
Share
Improve this question
asked Jan 31 at 19:15
garrettlynchirlgarrettlynchirl
91011 silver badges24 bronze badges
2 Answers
Reset to default 2The 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
}
Many thanks to @Moe for the help, I finally got this working thanks to him and I want to leave a trace of what works for others because (to me) this was insanely difficult and I still don't fully understand everything about how it works.
I'm only going to show the specific code for remember/mutableStateListOf here i.e. where it goes in the main class and then composable and, for the moment, I'm not worrying about the blocking issue mentioned above - this is a simplest, probably poorly implemented, but working solution. Note that it's also not everything you need, all the compose layout is missing. Here is what's in the mainactivity class:
class MainActivity : ComponentActivity() {
// get 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)
override fun onCreate(savedInstanceState: Bundle?) {
setContent {
CameraApp1Theme {
// create a mutablestatelistof and remember it for jetpack compose
val bitmaps = remember { mutableStateListOf<Bitmap>() }
// get a list of bitmaps of the images and add it to the bitmaps list
val loadedBitmaps = getBitmapList(fileList)
bitmaps.clear()
bitmaps.addAll(loadedBitmaps)
BottomSheetScaffold(
scaffoldState = scaffoldState,
sheetContent = {
PhotoBottomSheetContent(
// pass bitmaps to the composable
bitmaps = bitmaps,
modifier = Modifier.fillMaxWidth()
)
}
)
{
IconButton(
// triggered when the user open the photosheet
onClick = {
// read in a list of images in the images folder (update)
fileList = imageReaderNew(outputDirectory)
// get a list of bitmaps of the images and add it to the bitmaps list to update it
val loadedBitmaps = getBitmapList(fileList)
bitmaps.clear()
bitmaps.addAll(loadedBitmaps)
}
)
{
}
}
}
}
}
// Get output directory for photos
private fun getOutputDirectory(): File {
//... get the directory here (internal or external etc.) ...
// return absolute path to directory
return fullpath
}
// Read in an arraylist of all saved images for this app
private fun imageReaderNew(root: File): ArrayList<File> {
//... build the list here ...
// return filelist arraylist
return fileList
}
private fun getBitmapList(fileList: ArrayList<File>): ArrayList<Bitmap> {
// set up an empty bitmaps arraylist
val bitmaps: ArrayList<Bitmap> = ArrayList()
//... build the list here ...
// return bitmaps arraylist
return bitmaps
}
}
Finally in the composable you will need to declare bitmaps like so:
@Composable
fun PhotoBottomSheetContent(
//this is the basic working one
bitmaps: List<Bitmap>
)
{
}