Laggy/Slow BottomNavigation 可组合项之间的导航 - Jetpack Compose
Laggy/Slow Navigation between BottomNavigation composables - Jetpack Compose
我正在使用具有 4 个可组合项的 BottomNavigation
。它们都有一个 LazyColumn
,LazyColumn
中的每个项目都有使用 Coil for Jetpack Compose 从网络填充的图像。类似于 Twitter/YouTube.
当我在这些项目之间导航时,可组合项会被销毁并仅在导航回它们时重新组合。在这些可组合项之间导航时,甚至线圈图像也会被清除并重新获取(从内存或本地存储)。这当然是预期的行为。
问题是这导致它们之间的导航速度太慢。线圈图像需要大约 400 毫秒到 700 毫秒才能为每次导航加载图像。 YouTube/LinkedIn 等应用在其 BottomBar
导航中几乎是即时的。
当我为此使用 XML 时,我会使用 appear/disappear 逻辑制作片段(用作底部导航项)以避免在它们之间导航时出现此时间延迟。
如何使用 Compose 实现同样的效果?
我正在使用以下版本:
//compose navigation
implementation "androidx.navigation:navigation-compose:2.4.0-beta01"
implementation "com.google.accompanist:accompanist-navigation-animation:0.21.0-beta"
好吧,我在使用 emulator or phone
时遇到了同样的问题,两者都适用于简单的小型可组合项。当我创建更复杂的 Composable 并尝试为导航设置动画时,使用伴奏动画库会变得非常缓慢。
但后来我尝试构建发布 APK 文件,因为它通常经过优化并且速度更快,这将显着加快您的应用程序。 Here is link on how you can generate signed APK 然后将它安装到您的 phone 或模拟器上,看看是否能解决您的问题!
您还可以检查是否不小心从清单中禁用了硬件加速。确保在 activity 标签中设置 android:hardwareAccelerated="true"
。
如果这也没有帮助,那么您必须实现自己的动画并使用 Shared ViewModel 进行通信并触发从一个 Composable 到另一个 Composable 的转换。这个想法是,您可以使用修饰符 offset
属性 来 show/hide Composable,方法是将其放在屏幕外。
首先设置您的 ViewModel,并添加可变状态变量,这将触发从主页到设置的转换,反之亦然。
这不是最佳做法,因为无法像通常使用普通导航那样直接将数据从一个可组合项传递到另一个可组合项。但是您仍然可以使用 Shared ViewModel 共享数据。使用这种方法,它不会重组您的可组合对象,因此速度非常快。到目前为止,即使在某些具有 2GB RAM 的 old/slow 设备上,我也没有遇到任何内存不足异常的问题。
class SharedViewModel : ViewModel() {
// changing this mutable state will trigger the transition animation
private val _switchHomeToSetting = mutableStateOf(true)
val switchHomeToSetting: State<Boolean> = _switchHomeToSetting
fun switchHomeToSettings() {
_switchHomeToSetting.value = !_switchHomeToSetting.value
}
}
现在分别创建两个可组合函数 Home 和 Settings
@Composable
fun HomeScreen(viewModel: SharedViewModel) {
// draw your subcomponents
}
@Composable
fun SettingsScreen(viewModel: SharedViewModel) {
// draw your subcomponents
}
最后在 main 中初始化动画 activity
class MainActivity : ComponentActivity() {
val viewModel by viewModels<CityWeatherViewModel>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
// set your offset animation
val density = LocalDensity.current
val width = with(density) { (1.adw).toPx() }
val animatedOffsetX: Float by animateFloatAsState(
targetValue = if (!viewModel.switchHomeToSetting.value) 0f else width,
animationSpec = tween(1200)
)
// Home screen
Box(
modifier = Modifier
.fillMaxSize()
.offset { IntOffset((-width + animatedOffsetX).toInt(), 0) }
) {
HomeScreen(viewModel = viewModel)
}
// Settings screen
Box(
modifier = Modifier
.fillMaxSize()
.offset { IntOffset(animatedOffsetX.toInt(), 0) }
) {
SettingsScreen(viewModel = viewModel)
}
}
}
}
这是使用 Composable Navigation, together with the Accompanist Animation 的结果。如您所见,它确实非常滞后
现在这是使用我们的自定义动画的结果,它非常流畅,因为没有重组可组合项。
我正在使用具有 4 个可组合项的 BottomNavigation
。它们都有一个 LazyColumn
,LazyColumn
中的每个项目都有使用 Coil for Jetpack Compose 从网络填充的图像。类似于 Twitter/YouTube.
当我在这些项目之间导航时,可组合项会被销毁并仅在导航回它们时重新组合。在这些可组合项之间导航时,甚至线圈图像也会被清除并重新获取(从内存或本地存储)。这当然是预期的行为。
问题是这导致它们之间的导航速度太慢。线圈图像需要大约 400 毫秒到 700 毫秒才能为每次导航加载图像。 YouTube/LinkedIn 等应用在其 BottomBar
导航中几乎是即时的。
当我为此使用 XML 时,我会使用 appear/disappear 逻辑制作片段(用作底部导航项)以避免在它们之间导航时出现此时间延迟。
如何使用 Compose 实现同样的效果?
我正在使用以下版本:
//compose navigation
implementation "androidx.navigation:navigation-compose:2.4.0-beta01"
implementation "com.google.accompanist:accompanist-navigation-animation:0.21.0-beta"
好吧,我在使用 emulator or phone
时遇到了同样的问题,两者都适用于简单的小型可组合项。当我创建更复杂的 Composable 并尝试为导航设置动画时,使用伴奏动画库会变得非常缓慢。
但后来我尝试构建发布 APK 文件,因为它通常经过优化并且速度更快,这将显着加快您的应用程序。 Here is link on how you can generate signed APK 然后将它安装到您的 phone 或模拟器上,看看是否能解决您的问题!
您还可以检查是否不小心从清单中禁用了硬件加速。确保在 activity 标签中设置 android:hardwareAccelerated="true"
。
如果这也没有帮助,那么您必须实现自己的动画并使用 Shared ViewModel 进行通信并触发从一个 Composable 到另一个 Composable 的转换。这个想法是,您可以使用修饰符 offset
属性 来 show/hide Composable,方法是将其放在屏幕外。
首先设置您的 ViewModel,并添加可变状态变量,这将触发从主页到设置的转换,反之亦然。
这不是最佳做法,因为无法像通常使用普通导航那样直接将数据从一个可组合项传递到另一个可组合项。但是您仍然可以使用 Shared ViewModel 共享数据。使用这种方法,它不会重组您的可组合对象,因此速度非常快。到目前为止,即使在某些具有 2GB RAM 的 old/slow 设备上,我也没有遇到任何内存不足异常的问题。
class SharedViewModel : ViewModel() {
// changing this mutable state will trigger the transition animation
private val _switchHomeToSetting = mutableStateOf(true)
val switchHomeToSetting: State<Boolean> = _switchHomeToSetting
fun switchHomeToSettings() {
_switchHomeToSetting.value = !_switchHomeToSetting.value
}
}
现在分别创建两个可组合函数 Home 和 Settings
@Composable
fun HomeScreen(viewModel: SharedViewModel) {
// draw your subcomponents
}
@Composable
fun SettingsScreen(viewModel: SharedViewModel) {
// draw your subcomponents
}
最后在 main 中初始化动画 activity
class MainActivity : ComponentActivity() {
val viewModel by viewModels<CityWeatherViewModel>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
// set your offset animation
val density = LocalDensity.current
val width = with(density) { (1.adw).toPx() }
val animatedOffsetX: Float by animateFloatAsState(
targetValue = if (!viewModel.switchHomeToSetting.value) 0f else width,
animationSpec = tween(1200)
)
// Home screen
Box(
modifier = Modifier
.fillMaxSize()
.offset { IntOffset((-width + animatedOffsetX).toInt(), 0) }
) {
HomeScreen(viewModel = viewModel)
}
// Settings screen
Box(
modifier = Modifier
.fillMaxSize()
.offset { IntOffset(animatedOffsetX.toInt(), 0) }
) {
SettingsScreen(viewModel = viewModel)
}
}
}
}
这是使用 Composable Navigation, together with the Accompanist Animation 的结果。如您所见,它确实非常滞后
现在这是使用我们的自定义动画的结果,它非常流畅,因为没有重组可组合项。