Jetpack Compose lazyrow 比 xml 上的 recyclerView 慢得多

Ped*_*ira 0 optimization android lazy-loading android-xml android-jetpack-compose

我正在为非常有限的硬件开发一个应用程序,并决定使用 jetpack compose。

当我需要显示卡片列表并且用于它的惰性行变得非常滞后时,问题就出现了。为了进行比较,我选择了一个带有 recyclerView 的示例项目,并用它来显示大致相同的卡片列表,并且滚动尽可能平滑。jetpack compose 本质上比 xml view 慢还是我做错了什么?

撰写代码(我无法准确分享我的代码,但可组合的卡片只是一张带有一些图像、图标和文本的卡片):

@Composable
fun mainComposable(){
    ...
    cardList = remember{ arrayListOf(...) }
    lazyList(cardList)
    ...
}

@Composable
fun lazyList(
cardList: List<CardContent>,
){
    LazyRow(
        horizontalArrangement = Arrangement.spacedBy(16.dp),
        contentPadding = PaddingValues(horizontal = 32.dp)

        ) {
        items(
            items = cardList,
            key = { it.id }) { item ->
            CardComposable(
                content = item
            )
        }
    }
}


Run Code Online (Sandbox Code Playgroud)

我已经花了一些时间搜索,所以我发现了很多优化,比如在发布模式下运行,在 build.gradle 上将 minifyEnabled 和收缩资源设置为 true,在 gradle.properties 中将 android.enableR8.fullMode 设置为 true,使用 LazyRow 上的键他们有所帮助,但滚动仍然比带有 recyclerView 的等效 xml 视图应用程序慢。

编辑:添加了 CardComposable 代码


@Composable
fun CardComposable(
    content: Content,
) {

    Card(
        shape = RoundedCornerShape(8.dp),
        elevation = 1.dp,
        modifier = Modifier
            .width(216.dp)
            .height(308.dp)
    ) {
        Column {

            Box(contentAlignment = Alignment.TopEnd) {
                Image(
                    painter = painterResource(id = content.image),
                    modifier = Modifier
                        .width(216.dp)
                        .height(164.dp)
                )
                Box(
                    contentAlignment = Alignment.Center,
                    modifier = Modifier.padding(8.dp)
                ) {
                    Image(
                        painter = painterResource(id = R.drawable.button_background),
                        modifier = Modifier
                            .width(40.dp)
                            .height(40.dp)
                    )
                    Icon(
                        painter = painterResource(id = R.drawable.button),
                        modifier = Modifier
                            .width(16.dp)
                            .height(16.dp),
                        tint = GenericRedColor
                    )
                }
            }

            Column(
                modifier = Modifier
                    .padding(start = 16.dp)
            ) {

                Row(verticalAlignment = Alignment.CenterVertically) {
                    Text(
                        text = content.Name,
                        maxLines = 2,
                        color = GenericBlackColor,
                        fontSize = 16.sp,
                        fontWeight = FontWeight(500),
                        overflow = TextOverflow.Ellipsis,
                        modifier = Modifier
                            .width(134.dp)
                            .padding(top = 16.dp)
                    )

                    Box(
                        contentAlignment = Alignment.Center,
                        modifier = Modifier.padding(start = 16.dp, top = 8.dp)
                    ) {
                        Icon(
                            painter = painterResource(id = R.drawable.square_button),
                            modifier = Modifier
                                .width(32.dp)
                                .height(32.dp),
                            tint = GenericRedColor
                        )
                        Icon(
                            painter = painterResource(id = R.drawable.button_icon),
                            modifier = Modifier
                                .width(16.dp)
                                .height(16.dp),
                            tint = GenericWhiteColor
                        )
                    }
                }

                Text(
                    text = content.contentType,
                    color = GenericLightGrayColor2,
                    fontSize = 14.sp,
                    modifier = Modifier.padding(top = 8.dp)
                )

                Row(
                    horizontalArrangement = Arrangement.spacedBy(26.dp),
                    modifier = Modifier.padding(top = 24.dp)
                ) {

                    val iconModifier = Modifier
                        .padding(end = 4.dp)
                        .width(12.dp)
                        .height(12.dp)

                    Row(verticalAlignment = Alignment.CenterVertically) {
                        Icon(
                            painter = painterResource(R.drawable.icon_1),
                            modifier = iconModifier,
                            tint = GenericLightGrayColor2
                        )
                        Text(
                            text = content.text_1,
                            fontSize = 14.sp,
                            color = GenericLightGrayColor2
                        )
           
                        Icon(
                            painter = painterResource(R.drawable.icon_2),
                            modifier = iconModifier,
                            tint = GenericLightGrayColor2
                        )
                        Text(
                            text = content.text2,
                            fontSize = 14.sp,
                            color = GenericLightGrayColor2
                        )
      
                        Icon(
                            painter = painterResource(R.drawable.icon_3),
                            modifier = iconModifier,
                            tint = GenericLightGrayColor2
                        )
                        Text(
                            text = content.text3,
                            fontSize = 14.sp,
                            color = GenericLightGrayColor2
                        )
                    }
                }
            }
        }
    }
}


Run Code Online (Sandbox Code Playgroud)

Ama*_*mal 6

Jetpack Compose 是一个单独的库,不包含在 Android 操作系统中。因此,库中的代码应该在第一次运行时进行即时 (JIT)编译。这使得它本质上比基于 Android View 的代码慢,后者是提前编译 (AOT) 的,并且二进制文件存储在设备的操作系统内。

将 Jetpack Compose 作为独立库的设计决策也有其优点。无论 Android 操作系统版本如何,它都可以更轻松地更新和使用不同版本的库,并实现 compose 和 android 版本之间的向后兼容性。

在 iOS 中,Swift 采用了另一种方法,Swift 二进制文件是提前编译并包含在操作系统中的。这是除了苹果的懒惰之外阻碍 iOS 向后兼容的主要原因之一。

关于 RecyclerView 和 LazyLists 之间的性能差异,LazyLists 的性能明显低于 RecyclerView。这有多种原因。我认为这主要是因为 Compose 是一个较新的库并且正在不断改进。LazyLists 早期版本的性能要差得多。在即将推出的 compose 版本中,性能将进一步提高。

目前,由于 Jetpack Compose 与基于 Android View 的代码具有互操作性,因此您可以在 Compose 中使用 RecyclerView,并且性能开销最小。使用AndroidView()Jetpack Compose 中的函数。

@Composable
fun MyView(data: State<List<Item>>) {
    //This function enables Compose to interop with View based code.
    AndroidView(
        factory = { context ->
            RecyclerView(context).apply {
                layoutParams = ViewGroup.LayoutParams(MATCH_PARENT, WRAP_CONTENT)
                layoutManager = LinearLayoutManager(context)
                adapter = ItemListAdapter().also { it.submitList().value }
            }
        },
        update = { recyclerView ->
            //Callback that runs on each recomposition.
        }
    )
}
Run Code Online (Sandbox Code Playgroud)