Compose Beta is expected to release soon. People t...
# compose
o
Compose Beta is expected to release soon. People that already are using Compose, how is the performance compared to the Android View system?
😭 3
s
Unfortunately, On slightly older phones performance is not optimal as compare to View system.
z
if you want to replace RecyclerView, wait for couple of versions then.
s
For me it's like 80% performance of the view system
d
Noticeably worse, honestly... Probably needs both internal optimisation and guidance on how to write optimal code for it.
💯 2
a
Please send us example code for cases that don't perform as well as you would expect or like via the issue tracker and we can turn them into test cases to analyze and chase before 1.0. We're currently tracking performance work in the following areas:
Composition itself: in this area we're looking to separate and simplify the process of initial composition vs. updates, which should lead to less branching code and higher performance. We also have some tuning to do of some of the internal composition data structures. Some of you have noted the experimental multithreading API as well, which will get composition off the main thread and allow for different elements to [re]compose concurrently or on different threads altogether - think different lazy list items in parallel. Many low-end Android devices have several low-powered CPU cores available that this can take advantage of.
mind blown 1
❤️ 12
Measure and layout: in our current benchmark dashboards this is all in pretty good shape and generally outperforming views. We're pretty happy with this, as it bears out the changed measure/layout APIs from views, where views had previously hit a ceiling from not having enough information to work with during relayout and layout invalidation.
There are, however, a number of cases where our initial layout modifier APIs that have been around since early alphas force a return to recomposition to change things rather than relayout alone. You can see this in some of the offset modifiers - note that the newer variants accept lambdas and not direct sizing or offset parameters - this allows us to skip composition entirely and work only in layout when snapshot state read in those lambdas change.
Lazy lists and scrolling performance there are an area of active investigation. The folks working on these components have been on the bleeding edge of some other composition infrastructure work we've been doing, and some more performance optimizations are yet to come there.
(This is one we know is critical for all of you and it's getting a lot of attention; some of the supporting work is pretty deep in the stack and so it's taken some time.)
🙏 6
The team has largely prioritized API stabilization for the past few months to try to reduce the churn all of you feel when we update from release to release, so that it's easier for you all to stay up to date. The lambda-based modifiers are one example of this where we've set things in place to optimize performance at that API level, even though in some cases the actual optimizations themselves haven't been implemented yet
But we really would love specific test cases from you all! It's hard for us to unlearn the things we know about the system to write test cases that are representative of what people try first without that deep context in their heads, and we tend to write test cases that hit all of the happy paths without thinking about it. The more, the better!
Additionally, we do assume the kinds of optimizations r8 performs for release builds. If you're not checking release builds with r8 optimizations enabled, please compare with that as well.
s
Thanks, Good to know about all the work in terms of performance improvement is being done, in my case i have simple list item with icon resource and some animation for each item when user tap on item, but Unfortunately it has huge performance issue, even after removing animation as well
Copy code
@Composable
fun TeamItem(club: Club,
             selectedClubs: List<Club> = emptyList(),
             onItemClicked: (Club) -> Unit) {
    val isSelected = selectedClubs.contains(club)
    val color: Color by animateColorAsState(
        if (isSelected) MaterialTheme.colors.primary else MaterialTheme.colors.onBackground
    )
    val transition = updateTransition(
        targetState = if (isSelected) SelectionState.Selected else SelectionState.Unselected
    )
    val selectedAlpha by transition.animateFloat { state ->
        when (state) {
            SelectionState.Unselected -> 0f
            SelectionState.Selected -> 1f
        }
    }
    val checkScale by transition.animateFloat { state ->
        when (state) {
            SelectionState.Unselected -> 0f
            SelectionState.Selected -> 1f
        }
    }

    
    Column(horizontalAlignment = Alignment.CenterHorizontally,
        modifier = Modifier
            .padding(Padding8dp)
            .clickable(onClick = {
                club.isSelected.value = !club.isSelected.value
                onItemClicked(club)
            })
    ) {

        Box {
            Image(
                painterResource(id = club.teamLogoDrawable),
                contentScale = ContentScale.Fit,
                modifier = Modifier.preferredSize(80.dp),
                contentDescription = null
            )

            Surface(
                color = MaterialTheme.colors.primary,
                shape = CircleShape,
                elevation = 4.dp,
                modifier = Modifier.size(25.dp)
                    .align(Alignment.CenterEnd)
                    .offset(x = 5.dp)
                    .scale(checkScale)
            ) {
                Icon(
                    imageVector = Icons.Filled.Done,
                    contentDescription = null,
                    tint = MaterialTheme.colors.onPrimary.copy(alpha = selectedAlpha),
                    modifier = Modifier.padding(4.dp)
                )
            }
        }


        VerticleSpace(Padding4dp)

        Text(
            text = club.name,
            maxLines = 2,
            style = facrNormal16BodyText().copy(color = color)
        )
    }
}
And i'm using it like
Copy code
LazyVerticalGrid(
    modifier = Modifier.fillMaxSize(),
    cells = GridCells.Fixed(column),
   // contentPadding = PaddingValues(top = Constants.Padding8dp)
) {

    itemsGridIndexed(items) { _, item ->
        item?.let {
            itemContent(it)
        }
    }
}
a
Thanks! If you and others could put these into gists or similar and link them, if not tickets on the issue tracker, that would make them very easy for the team to reference in issues we open to trace specific cases.
👍 1
How often are items in that grid null?
s
Actually the items are coming form PagingItems. https://gist.github.com/shakil807g/13a4074d7589405be35e102e3347db86
a
that's helpful, thanks! I'll pass it along to the team this week
👍 4