is there any discernible difference between doing ...
# compose
d
is there any discernible difference between doing this
Copy code
LazyColumn {
  item {
    if (someState.value) { ListItem(...) }
  }
}
and this
Copy code
LazyColumn {
  if (someState.value) {
    item {
      ListItem(...)
    }
  }
}
Any performance considerations in either case? Which is better?
s
What will the
key
of the
item {}
be for your item on #1 if the item does not exist?
d
Not using explicit keys, using default ones...
s
Maybe this is giving you a hint that you should use proper keys for your list and go with #2. That’s what I’d do at least. Otherwise you may have a list with 200 items, and all of them are trying to be rendered, but all of them emit no UI. Sounds to me like you’d just not want them to be called at all in the first place. Besides this way of thinking, I don’t have any hard data to give you though if this is better or not 🤷‍♂️ But I wouldn’t expect the best of performance if you’re not using the key and the contentType parameters of the lazy list apis.
d
Thanks. I asked because I'm writing a certain Detekt rule and occasionally it would suggest this kind of change (going from #1 to #2), so I thought if that turns out to be a bad advice, I'd modify the rule to not suggest that.
a
Purely conjecture, but imo mentioning item{} means there's something for the Lazy Column to manage. So I prefer using conditionals outside in such a scenario. Happy to be corrected tho, if I'm wrong.
👍 1
c
One important thing to note: the
content
lambda of
LazyColumn
is NOT
@Composable
. I’m pretty sure this means that in the case of #2, if the
someState.value
value changes the entire
LazyColumn
will be recomposed, not just the wrapped item. If you have individual items each with their own visibility conditions, I think you should keep that as a regular
Column
. I also suspect that having individual items with different visibility means their content is also going to be different, so the underlying views won’t really be recycled like they would if you’re actually rendering a
List
of items, so the perfomance gains of being lazy might not cover the overhead of recreating those views as it’s scrolled
💡 1
👀 1
1
m
The second one is more performant AFAIK, also according to ian lake's comment on this thread: https://kotlinlang.slack.com/archives/CJLTWPH7S/p1656641427562559?thread_ts=1656639153.030769&cid=CJLTWPH7S
👍 3
d
so the perfomance gains of being lazy might not cover the overhead of recreating those views as it’s scrolled
Switching to Column is not always possible, consider this usecase: A screen with 3 sections, first two are static, but optional, and last "section" is a list of 1000 items. And all 3 must be scrolled together, when they are present. In this case the most natural solution is to use LazyColumn
1
Thanks @MR3Y Then my rule makes sense for
item
too. It will suggest replacing this (in absence of other layout side-effects)
Copy code
Column {
  if (condition) {
    Text()
  }
}
with this
Copy code
if (condition) {
  Column {
    Text()
  }
}
(
item
case falls in this category) Will be adding it to our detekt-rules-compose rule set.
a
Does the scroll to item work properly if there are empty items 🤔 . I think you may get unexpected results.
👀 1
m
i would filter the items in the viewmodel if i could
1
d
If items are "headers" with static text, they don't really belong in the viewmodel, view state should contain something like "headerVisible: Boolean" from which items' ui is derived.
a
not calling “item” at all if the item is not needed is more efficient as we don’t even need to compose this item only to realise that this item is fully empty. also there is another hint on not composing empty or 0 sized content as part of lazy list item - https://developer.android.com/jetpack/compose/lists#avoid-0-size-items
1
d
Great, thank you!
m
@dimsuz who said they dont belong in the viewModel
d
I did 🙂
From my point of view, ViewModels should be responsible for UI interaction logic and Compose-layer should be responsible for rendering it. ViewModel produces "view states" which are purely data, and Compose renders this data. Hence ViewModel knows nothing about Compose (or Fragment or whatever). And it can also be even unit tested this way more easily.
💯 1
I guess more correct name for ViewModel would be Presenter or something like this.
👍 1
a
Well, based on your definition, aren't item headers also considered as
static data
?? making them eligible for residence in Viewmodel??
d
Yes, static data, while my definition mentioned "interaction", so ViewModel and states it produces are about changing data. I.e. if a title of my header would change, I surely would put it in the ViewState, managed by a ViewModel. If it never changes, it will just be set in a composable function (read from resource or whatever).
a
at aSoft (where I work), if something like that is not eligible for being placed on a resource folder, we put it in the ViewModel. Our reasons are 1. The UI should at the very best just do UI related things. (e.g., If we need to change the header from "time", to "duration"), we won't have to touch the UI components at all 2. We share our ViewModels accross different UI frameworks (Specifically Compose and React), having these kind of static (yet shared) data in a central place makes it very convinient
👀 1
1
d
Agreed, especially in presence of 2. it looks like you have good reasons to do so. In my case I keep it simple until it needs to be changed 🙂
210 Views