i am still searching for good documentation with e...
# compose-desktop
z
i am still searching for good documentation with examples for compose desktop. docs that are not android but JVM desktop specific. and also that explain how LazyColumn really works. its supposed to be Recyclerview for desktop. but how is it properly used? for example how do i update 1 single item in the items list correctly? when there are 20000 items in it. all docs i read until now only explain the things that are clear anyway and skip the rest any links? and good understanable examples for large scroll item list?
a
99% of Jetpack Compose examples apply to the desktop too. You can find documentation for desktop-specific topics here: https://github.com/JetBrains/compose-multiplatform/blob/master/tutorials/README.md#desktop
LazyColumn has nothing desktop-specific, except maybe scrollbars.
👍🏻 1
c
LazyColumn is intended to be similar to RecyclerView, but the main difference is that it isn’t all that different than rendering the list with a standard for-loop over a list of items, as far as user code is concerned. Rendering a list with LazyColumn vs a for-loop looks almost identical, so the difference is the optimizations that happen under the hood. For example:
Copy code
@Composable
fun DataList(data: List<String>) { 
    // using LazyColumn
    LazyColumn { 
        items(data) { item ->
            DataListItem(item)
        }
    }
    
    // using for-loop
    data.forEach { item ->
        DataListItem(item)
    }
}

@Composable
fun DataListItem(data: String) {
    // ...
}
RecyclerView required a bunch of extra boilerplate and special handling of the data because the View system is not natively designed to render UI based on data like that. But Compose is already designed to make the UI purely a function of data, so the optimization of LazyColumn is just that: an optimization. Use it when it makes sense, semantically, which is when you’re rendering a large list of data.
z
so then when only 1 single item in a list of 20 thousand items change, i still need to give a new state with 20.000 items? and the magically compose will only render the one that has changed
a
You’re not giving it a state with 20k items.
You’re giving it a function that can generate 20k items.
That function will only be called to generate the items that are actually on the screen.
z
ok. but also how do i handle this in the data functions? if i have some data structure with 20k items. and i want to change 1 item quickly (a download progressbar for example). i am still missing examples that i can properly understand.
a
You can change in the item itself.
there the state is always copied it seems
a
Copy code
var progress by mutableStateOf(0)

@OptIn(DelicateCoroutinesApi::class)
fun main() {
    GlobalScope.launch {
        while (progress < 100) {
            delay(100)
            progress += 1
        }
    }

    singleWindowApplication {
        LazyColumn(Modifier.width(400.dp).fillMaxHeight()) {
            item {
                MyProgressBar()
            }

            items(1000) {
                Text(it.toString(), Modifier.padding(16.dp))
            }
        }
    }
}

@Composable
fun MyProgressBar() {
    Text("${progress}%")
}
c
One tip: Compose can be a bit tricky to understand logically, and many of these questions can be answered simply by running your code and seeing how things react. The compiler and runtime are very clever and you might be able to get away with not thinking much about the specifics of what it’s doing. It is a declarative language after all, so just declare your intent and see if it “feels” right to you, or if it performs poorly. If it doesn’t seem to be performing like you expect, then you can dig into it. But until then, you can often just assume that it is working correctly. So in this case, try creating a list of 20k items, hold it in a
mutableStateOf()
with a
LazyColumn
, and then replace that list with one containing the changed value (or hold the list with
mutableStateListOf()
and use its functions to update the list). If the performance there si good, try increasing the size of the list to see where (or if) if breaks down
z
thats sort of how i am doing it. being new to compose (not new to coding) i still have trouble fully grasping state mutablestate statelistof collectasstate and the likes. maybe because english is not my native langugage. i read a ton of docs and all do not make it really clear to me. when to use which, what do they actually do under the hood?
as example i copied this from the example:
Copy code
val messagestore = CoroutineScope(SupervisorJob()).createMessageStore()
because it does what i want. but i have not idea what that actually means
c
In general, if you are managing your data in a ViewModel or Store, like is done in the sample you linked above, you don’t need
mutableStateListOf()
. That’s used for the case where you are updating a list’s content purely from Compose and not in a ViewModel. Apart from that,
mutableStateOf()
is how Compose knows when to recompose. It should hold an immutable value, and when that value is replaced, Compose will recompose and update the relevant parts of the UI. This process is smart and will skip anything that has not changed, and this includes if only a single property of an object has changed.
collectAsState()
adapts a
StateFlow
to Compose by literally just collecting the flow and updating a
mutableStateOf()
variable for you.
For creating the store, since the function signature of
CoroutineScope.createStore()
is not
@Composable
, it basically means that the store it creates lives outside of Compose. You can use any CoroutineScope you have to create and manage the store. This can be tied to a custom global CoroutineScope in Desktop,
viewModelScope
or
lifecycleScope
in an Android Fragment, or even
rememberLifecycleScope()
to tie it to a specific Composable function. Whatever scope is used to create the store will determine when that store is active. If the associated coroutineScope is cancelled, the store will be closed and it will no longer process new values. But it lives on its own outside of Compose, and is only tied to compose when you collect its stateFlow using
mesageStore.stateFlow.collectAsState()
z
thank for all the replies
thats already makes things a bit more clear