【问题标题】:How to "warm up" Jetpack Compose before showing UI?如何在显示 UI 之前“预热”Jetpack Compose?
【发布时间】:2022-07-20 16:12:34
【问题描述】:

我使用 Jetpack Compose 实现了可折叠应用栏,但在应用启动时遇到性能下降。

这是我的屏幕:

@Composable
private fun PerformanceTestScreen() {
    val state = rememberCollapsingToolbarScaffoldState()

    CollapsingToolbarScaffold(
        modifier = Modifier.fillMaxSize(),
        state = state,
        scrollStrategy = ScrollStrategy.EnterAlwaysCollapsed,
        toolbarModifier = Modifier.background(MaterialTheme.colors.primary),
        toolbar = {
            val timestamp = System.currentTimeMillis()

            Surface(
                modifier = Modifier
                    .height(IntrinsicSize.Min)
                    .parallax(0.5f),
                color = MaterialTheme.colors.primarySurface,
                elevation = AppBarDefaults.TopAppBarElevation,
            ) {
                MyAppBarContent(
                    value1 = "123",
                    value2 = "345",
                    state = state
                )
            }

            MyExpandedAppBar(
                modifier = Modifier.road(Alignment.BottomStart, Alignment.BottomStart),
                state = state
            )
            // Collapsing toolbar collapses its size as small as the that of a smallest child (this)
            MyCollapsedAppBar(
                state = state
            )

            Log.d("perf", "toolbar draw speed = ${System.currentTimeMillis() - timestamp}")
        }
    ) {
        LazyColumn(
            modifier = Modifier
                .fillMaxSize()
        ) {
            items(
                List(100) { "Hello World!! $it" }
            ) {
                Text(
                    text = it,
                    modifier = Modifier
                        .fillMaxWidth()
                        .padding(16.dp)
                )
            }
        }
    }
}

这是我得到的日志:

2021-11-24 11:08:33.112 3639-3639/me.onebone.toolbar D/perf: toolbar draw speed = 182
2021-11-24 11:08:33.418 3639-3676/me.onebone.toolbar I/OpenGLRenderer: Davey! duration=860ms; Flags=1, IntendedVsync=5315700621180, Vsync=5315783954510, OldestInputEvent=9223372036854775807, NewestInputEvent=0, HandleInputStart=5315784916372, AnimationStart=5315784923559, PerformTraversalsStart=5315785127049, DrawStart=5316511379778, SyncQueued=5316547103948, SyncStart=5316547505927, IssueDrawCommandsStart=5316547652698, SwapBuffers=5316560513324, FrameCompleted=5316561658637, DequeueBufferDuration=111146, QueueBufferDuration=333282, GpuCompleted=0, 
2021-11-24 11:08:33.478 3639-3676/me.onebone.toolbar I/OpenGLRenderer: Davey! duration=755ms; Flags=0, IntendedVsync=5315865424551, Vsync=5316565424523, OldestInputEvent=9223372036854775807, NewestInputEvent=0, HandleInputStart=5316582050462, AnimationStart=5316582062024, PerformTraversalsStart=5316603601401, DrawStart=5316603789683, SyncQueued=5316616305101, SyncStart=5316616895882, IssueDrawCommandsStart=5316617046507, SwapBuffers=5316620493070, FrameCompleted=5316621634476, DequeueBufferDuration=116041, QueueBufferDuration=272344, GpuCompleted=0, 
2021-11-24 11:08:34.486 3639-3639/me.onebone.toolbar D/perf: toolbar draw speed = 9
2021-11-24 11:08:34.561 3639-3639/me.onebone.toolbar D/perf: toolbar draw speed = 8
2021-11-24 11:08:34.625 3639-3639/me.onebone.toolbar D/perf: toolbar draw speed = 6
2021-11-24 11:08:34.683 3639-3639/me.onebone.toolbar D/perf: toolbar draw speed = 7
2021-11-24 11:08:34.739 3639-3639/me.onebone.toolbar D/perf: toolbar draw speed = 7
2021-11-24 11:08:34.796 3639-3639/me.onebone.toolbar D/perf: toolbar draw speed = 6
2021-11-24 11:08:34.853 3639-3639/me.onebone.toolbar D/perf: toolbar draw speed = 7
2021-11-24 11:08:34.902 3639-3639/me.onebone.toolbar D/perf: toolbar draw speed = 5
2021-11-24 11:08:34.956 3639-3639/me.onebone.toolbar D/perf: toolbar draw speed = 6
2021-11-24 11:08:35.011 3639-3639/me.onebone.toolbar D/perf: toolbar draw speed = 6
2021-11-24 11:08:35.061 3639-3639/me.onebone.toolbar D/perf: toolbar draw speed = 5
2021-11-24 11:08:35.106 3639-3639/me.onebone.toolbar D/perf: toolbar draw speed = 4
2021-11-24 11:08:35.151 3639-3639/me.onebone.toolbar D/perf: toolbar draw speed = 5
2021-11-24 11:08:35.199 3639-3639/me.onebone.toolbar D/perf: toolbar draw speed = 6
2021-11-24 11:08:35.244 3639-3639/me.onebone.toolbar D/perf: toolbar draw speed = 6
2021-11-24 11:08:35.286 3639-3639/me.onebone.toolbar D/perf: toolbar draw speed = 4
2021-11-24 11:08:35.330 3639-3639/me.onebone.toolbar D/perf: toolbar draw speed = 5
2021-11-24 11:08:35.371 3639-3639/me.onebone.toolbar D/perf: toolbar draw speed = 4
2021-11-24 11:08:35.411 3639-3639/me.onebone.toolbar D/perf: toolbar draw speed = 5
2021-11-24 11:08:35.449 3639-3639/me.onebone.toolbar D/perf: toolbar draw speed = 4
2021-11-24 11:08:35.488 3639-3639/me.onebone.toolbar D/perf: toolbar draw speed = 3
2021-11-24 11:08:35.525 3639-3639/me.onebone.toolbar D/perf: toolbar draw speed = 5
2021-11-24 11:08:35.562 3639-3639/me.onebone.toolbar D/perf: toolbar draw speed = 3
2021-11-24 11:08:35.596 3639-3639/me.onebone.toolbar D/perf: toolbar draw speed = 3
2021-11-24 11:08:35.663 3639-3639/me.onebone.toolbar D/perf: toolbar draw speed = 3
2021-11-24 11:08:35.696 3639-3639/me.onebone.toolbar D/perf: toolbar draw speed = 3
2021-11-24 11:08:35.728 3639-3639/me.onebone.toolbar D/perf: toolbar draw speed = 3
2021-11-24 11:08:35.794 3639-3639/me.onebone.toolbar D/perf: toolbar draw speed = 3
2021-11-24 11:08:35.827 3639-3639/me.onebone.toolbar D/perf: toolbar draw speed = 4
2021-11-24 11:08:35.860 3639-3639/me.onebone.toolbar D/perf: toolbar draw speed = 3
2021-11-24 11:08:35.897 3639-3639/me.onebone.toolbar D/perf: toolbar draw speed = 4
2021-11-24 11:08:35.935 3639-3639/me.onebone.toolbar D/perf: toolbar draw speed = 4
2021-11-24 11:08:35.979 3639-3639/me.onebone.toolbar D/perf: toolbar draw speed = 6
2021-11-24 11:08:36.016 3639-3639/me.onebone.toolbar D/perf: toolbar draw speed = 4
2021-11-24 11:08:36.214 3639-3639/me.onebone.toolbar D/perf: toolbar draw speed = 4
2021-11-24 11:08:36.248 3639-3639/me.onebone.toolbar D/perf: toolbar draw speed = 5
2021-11-24 11:08:36.278 3639-3639/me.onebone.toolbar D/perf: toolbar draw speed = 4
2021-11-24 11:08:36.308 3639-3639/me.onebone.toolbar D/perf: toolbar draw speed = 4
2021-11-24 11:08:36.339 3639-3639/me.onebone.toolbar D/perf: toolbar draw speed = 3
2021-11-24 11:08:36.370 3639-3639/me.onebone.toolbar D/perf: toolbar draw speed = 3
2021-11-24 11:08:36.403 3639-3639/me.onebone.toolbar D/perf: toolbar draw speed = 3
2021-11-24 11:08:36.431 3639-3639/me.onebone.toolbar D/perf: toolbar draw speed = 3
2021-11-24 11:08:36.463 3639-3639/me.onebone.toolbar D/perf: toolbar draw speed = 4
2021-11-24 11:08:36.494 3639-3639/me.onebone.toolbar D/perf: toolbar draw speed = 4
2021-11-24 11:08:36.524 3639-3639/me.onebone.toolbar D/perf: toolbar draw speed = 4
2021-11-24 11:08:36.553 3639-3639/me.onebone.toolbar D/perf: toolbar draw speed = 3
2021-11-24 11:08:36.582 3639-3639/me.onebone.toolbar D/perf: toolbar draw speed = 2
2021-11-24 11:08:36.622 3639-3639/me.onebone.toolbar D/perf: toolbar draw speed = 4
2021-11-24 11:08:36.652 3639-3639/me.onebone.toolbar D/perf: toolbar draw speed = 3
2021-11-24 11:08:36.681 3639-3639/me.onebone.toolbar D/perf: toolbar draw speed = 3
2021-11-24 11:08:36.708 3639-3639/me.onebone.toolbar D/perf: toolbar draw speed = 4
2021-11-24 11:08:36.734 3639-3639/me.onebone.toolbar D/perf: toolbar draw speed = 2
2021-11-24 11:08:36.762 3639-3639/me.onebone.toolbar D/perf: toolbar draw speed = 3
2021-11-24 11:08:36.788 3639-3639/me.onebone.toolbar D/perf: toolbar draw speed = 3
2021-11-24 11:08:36.820 3639-3639/me.onebone.toolbar D/perf: toolbar draw speed = 4
2021-11-24 11:08:36.847 3639-3639/me.onebone.toolbar D/perf: toolbar draw speed = 3
2021-11-24 11:08:36.875 3639-3639/me.onebone.toolbar D/perf: toolbar draw speed = 4
2021-11-24 11:08:36.900 3639-3639/me.onebone.toolbar D/perf: toolbar draw speed = 2
2021-11-24 11:08:36.926 3639-3639/me.onebone.toolbar D/perf: toolbar draw speed = 3
2021-11-24 11:08:36.954 3639-3639/me.onebone.toolbar D/perf: toolbar draw speed = 2
2021-11-24 11:08:36.979 3639-3639/me.onebone.toolbar D/perf: toolbar draw speed = 2
2021-11-24 11:08:37.004 3639-3639/me.onebone.toolbar D/perf: toolbar draw speed = 3
2021-11-24 11:08:37.028 3639-3639/me.onebone.toolbar D/perf: toolbar draw speed = 3
2021-11-24 11:08:37.053 3639-3639/me.onebone.toolbar D/perf: toolbar draw speed = 5
2021-11-24 11:08:37.076 3639-3639/me.onebone.toolbar D/perf: toolbar draw speed = 2
2021-11-24 11:08:37.102 3639-3639/me.onebone.toolbar D/perf: toolbar draw speed = 4
2021-11-24 11:08:37.126 3639-3639/me.onebone.toolbar D/perf: toolbar draw speed = 3
2021-11-24 11:08:37.149 3639-3639/me.onebone.toolbar D/perf: toolbar draw speed = 2
2021-11-24 11:08:37.194 3639-3639/me.onebone.toolbar D/perf: toolbar draw speed = 2
2021-11-24 11:08:37.218 3639-3639/me.onebone.toolbar D/perf: toolbar draw speed = 1
2021-11-24 11:08:37.239 3639-3639/me.onebone.toolbar D/perf: toolbar draw speed = 2

正如您所见,随着时间的推移,绘图性能会越来越好。通过反复试验,我设法找出默认 Material AppBars 最能降低生产力的地方。我不想编写自定义 AppBar,所以有没有办法在 UI 实际出现之前对其进行预热?

我使用compose-collapsing-toolbar lib,它的实现不是我性能下降的原因。我查过了。

这里是全屏代码:

import android.os.Bundle
import android.util.Log
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.annotation.FloatRange
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.IntrinsicSize
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.AppBarDefaults
import androidx.compose.material.Icon
import androidx.compose.material.IconButton
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Surface
import androidx.compose.material.Text
import androidx.compose.material.TopAppBar
import androidx.compose.material.contentColorFor
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.MoreVert
import androidx.compose.material.icons.filled.Share
import androidx.compose.material.primarySurface
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import me.onebone.toolbar.ui.theme.CollapsingToolbarTheme

class PerformanceTestActivity: ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            CollapsingToolbarTheme {
                Surface(color = MaterialTheme.colors.background) {
                    PerformanceTestScreen()
                }
            }
        }
    }
}

@Composable
private fun PerformanceTestScreen() {
    val state = rememberCollapsingToolbarScaffoldState()

    CollapsingToolbarScaffold(
        modifier = Modifier.fillMaxSize(),
        state = state,
        scrollStrategy = ScrollStrategy.EnterAlwaysCollapsed,
        snapStrategy = SnapStrategy(),
        toolbarModifier = Modifier.background(MaterialTheme.colors.primary),
        toolbar = {
            val timestamp = System.currentTimeMillis()

            Surface(
                modifier = Modifier
                    .height(IntrinsicSize.Min)
                    .parallax(0.5f),
                color = MaterialTheme.colors.primarySurface,
                elevation = AppBarDefaults.TopAppBarElevation,
            ) {
                MyAppBarContent(
                    value1 = "123",
                    value2 = "345",
                    state = state
                )
            }

            MyExpandedAppBar(
                modifier = Modifier.road(Alignment.BottomStart, Alignment.BottomStart),
                state = state
            )
            // Collapsing toolbar collapses its size as small as the that of a smallest child (this)
            MyCollapsedAppBar(
                state = state
            )

            Log.d("perf", "toolbar draw speed = ${System.currentTimeMillis() - timestamp}")
        }
    ) {
        LazyColumn(
            modifier = Modifier
                .fillMaxSize()
        ) {
            items(
                List(100) { "Hello World!! $it" }
            ) {
                Text(
                    text = it,
                    modifier = Modifier
                        .fillMaxWidth()
                        .padding(16.dp)
                )
            }
        }
    }
}

@Composable
private fun MyAppBarContent(
    modifier: Modifier = Modifier,
    value1: String,
    value2: String,
    state: CollapsingToolbarScaffoldState,
) {
    Box(
        modifier = modifier
            .fillMaxWidth()
            .graphicsLayer {
                alpha = state.toolbarState.progress.configureProgress(0.5f)
            }
            .alpha(state.toolbarState.progress.configureProgress(0.5f)),
        contentAlignment = Alignment.Center
    ) {
        Image(
            modifier = Modifier.fillMaxSize(),
            painter = painterResource(R.drawable.ic_launcher_foreground),
            contentDescription = null,
            contentScale = ContentScale.Crop
        )
        Row(
            modifier = Modifier
                .padding(horizontal = 16.dp, vertical = MaterialAppBarHeight)
                .fillMaxSize(),
            horizontalArrangement = Arrangement.SpaceBetween,
            verticalAlignment = Alignment.CenterVertically
        ) {
            MyTextTile(
                title = "title1",
                value = value1
            )
            MyTextTile(
                title = "title2",
                value = value2
            )
        }
    }
}


@Composable
private fun MyTextTile(
    modifier: Modifier = Modifier,
    title: String,
    value: String,
) {
    val fontScale = LocalContext.current.resources.configuration.fontScale

    Column(
        modifier = modifier.height(DashboardStatisticsTileHeight.times(fontScale)),
        horizontalAlignment = Alignment.CenterHorizontally,
    ) {
        Text(
            modifier = Modifier.padding(vertical = 8.dp),
            text = title
        )

        Box(
            modifier = Modifier
                .padding(bottom = 8.dp)
                .aspectRatio(1f)
                .border(
                    width = DashboardStatisticsTileBorderWidth,
                    color = MaterialTheme.colors.onPrimary,
                    shape = RoundedCornerShape(8.dp)
                ),
            contentAlignment = Alignment.Center
        ) {
            Text(
                modifier = Modifier
                    .padding(horizontal = DashboardStatisticsTileBorderWidth.times(2)),
                text = value,
            )
        }
    }
}

@Composable
private fun MyAppBar(
    modifier: Modifier = Modifier,
    title: @Composable () -> Unit,
    actions: @Composable RowScope.() -> Unit = {},
) {
    TopAppBar(
        modifier = modifier.height(MaterialAppBarHeight),
        title = title,
        actions = actions,
        backgroundColor = Color.Transparent,
        contentColor = contentColorFor(MaterialTheme.colors.primarySurface),
        elevation = 0.dp
    )
}

@Composable
private fun MyExpandedAppBar(
    modifier: Modifier = Modifier,
    state: CollapsingToolbarScaffoldState,
) {
    MyAppBar(
        modifier = modifier,
        title = {
            Text(
                modifier = Modifier
                    .alpha(state.toolbarState.progressReversed.configureProgress(0.5f)),
                text = stringResource(R.string.app_name),
                color = MaterialTheme.colors.onPrimary
            )
        },
        actions = {
            IconButton(
                modifier = Modifier
                    .alpha(state.toolbarState.progress.configureProgress(0.5f)),
                onClick = {}
            ) {
                // TODO by RareScrap: contentDescription
                // TODO by RareScrap: Use system localisation
                Icon(imageVector = Icons.Filled.Share, contentDescription = null)
            }
        }
    )
}

@Composable
private fun MyCollapsedAppBar(
    modifier: Modifier = Modifier,
    state: CollapsingToolbarScaffoldState,
) {
    MyAppBar(
        modifier = modifier,
        title = {
            Text(
                modifier = Modifier.alpha(state.toolbarState.progress),
                text = "R.string.my_progress",
                color = MaterialTheme.colors.onPrimary
            )
        },
        actions = {
            IconButton(onClick = {}) {
                Icon(
                    imageVector = Icons.Filled.MoreVert,
                    contentDescription = null
                )

            }
        }
    )
}

private val CollapsingToolbarState.progressReversed: Float
    get() = 1f - progress

private val DashboardStatisticsTileHeight = 118.dp
private val DashboardStatisticsTileBorderWidth = 5.dp
private val MaterialAppBarHeight = 56.dp

fun Float.configureProgress(@FloatRange(from = 0.0, to = 1.0) startAt: Float): Float {
    val start = (1f - startAt).coerceAtLeast(0f)
    val multiplier = 1f / start
    return (this - start) * multiplier
}

【问题讨论】:

标签: android performance android-jetpack-compose appbar collapsable


【解决方案1】:

当第一个包含 ComposeView 的片段出现时,我也遇到了这个性能问题,调用 onCreateView 需要 800 毫秒!我用Systrace做了一些分析,然后我在记者那里发现了这么多“VerifyClass androidx.compose.***”!大部分时间都花在加载 Compose 的框架代码上。Systrace Report

【讨论】:

  • “VerifyClass androidx.compose.***”的总数是1290,我还没有删除重复项
猜你喜欢
  • 2021-04-26
  • 1970-01-01
  • 2022-12-18
  • 1970-01-01
  • 2021-08-04
  • 2022-06-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多