1

Kotlin newbie here!

I'm trying to make a map that can be changed, but also where such a change will trigger recomposition. However, I'm hitting a conundrum and can't seem to find a way around it.

I understand that using something like this:

val someVar by remember {mutableStateOf(someMutableMap)}

is useless because it's trying to view a mutable state of objects which are themselves mutable. I understand why this doesn't work. However, I can't seem to find a way to use mutableStateOf() with a plain map because if I use a plain map, there's no way to add key / value pairs or to change the values once they're there. Makes sense, since that's what immutable means. But I need to be able to add to and change the map due to the nature of the app I'm trying to write.

I've tried:

-> Using a mutableStateOf(mutableMap), which gives me a warning about using mutable state on something that is itself mutable. This doesn't trigger recomposition, for obvious reasons.

-> Using a mutableStateOf(map), which does trigger recomposition, however, it also prevents me from adding to or changing the map, since there aren't any setters for immutable objects. This causes the function that builds the map (from a text file, but one headache at a time) to not work, along with basically everything else about the app, since the whole point is for the user to build this map.

I'm not expecting a silver-platter answer, but a little direction would be vastly appreciated. I can post code here if it will help.

Edric
  • 24,639
  • 13
  • 81
  • 91
Cj Amweg
  • 23
  • 3
  • What exactly is a `Map` used for here? Could a data class with immutable properties instead be more viable? – Edric Dec 12 '22 at 05:01
  • It certainly might be. Right now I'm using a `Map>` and it seems to be a little cumbersome to work with. Especially figuring out the correct syntax to edit the `List` part of the array, it hasn't been easy. Being fairly new to OOP in general, the `Map` seemed the easiest to get a handle on rather than going straight for the custom class option. – Cj Amweg Dec 12 '22 at 22:54

2 Answers2

3

The way to do this with read-only Maps is to create new read-only Maps. You can do this using the plus and minus operators. You can use += and -= for convenience. These create new read-only maps with the modification specified relative to the original map.

val someVar by remember { mutableStateOf(mapOf("key" to 1) }

// To add something, use + and a Pair:
someVar = someVar + "some other key" to 2
// or:
someVar += "some other key" to 2

// To remove something, use - and the key to remove
someVar = someVar - "key"
// or:
someVar -= "key"

There are more details here in the documentation. You can also add lists of pairs or maps to add a group of keys. Or you can remove lists of keys.

Tenfour04
  • 83,111
  • 11
  • 94
  • 154
  • I implemented this with `MutableStateMap` and it works out well for editing live data. The only thing now is that when trying to make the data persist and rebuild the `MutableStateMap` from a text file, it doesn't seem to want to do it. That's probably a whole 'nother question though. – Cj Amweg Dec 12 '22 at 22:59
2

You can use mutableStateMapOf to get a SnapshotStateMap which triggers recomposition when you add, remove or update existing item with new instance

val map: SnapshotStateMap<Int, String> = remember {
    mutableStateMapOf()
}

sample

@Composable
private fun MutableStateMapOfSample() {
    val map: SnapshotStateMap<Int, String> = remember {
        mutableStateMapOf()
    }

    var counter by remember {
        mutableStateOf(0)
    }

    Button(onClick = {
        map[counter] = "Value: $counter"
        counter++
    }) {
        Text("Add $counter")
    }
    
    LazyColumn(){
        items(items= map.keys.toList()) {
            Text("key: $it, value: ${map[it]}")
        }
    }
}

There is also List variant which is SnapshotStateList, mutableStateListOf, which triggers recomposition only for the updated item.

Jetpack Compose lazy column all items recomposes when a single item update

Thracian
  • 43,021
  • 16
  • 133
  • 222
  • I did end up using `MutableStateMap` for this problem and it works out very nicely for editing live data. I have other problems now related to rebuilding the array data from a file, but that's another question, I think. – Cj Amweg Dec 12 '22 at 23:16