无法让 Android Jetpack Compose BackHandler 工作

问题描述 投票:0回答:1

我正在尝试使用 Android Jetpack Compose 的 BackHandler 使用以下简化代码来拦截后退按钮的处理:

package com.example.backhandlertest

import androidx.activity.compose.BackHandler
import androidx.annotation.StringRes
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material3.Button
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.currentBackStackEntryAsState
import androidx.navigation.compose.rememberNavController


@Composable
fun BackHandlerTestApp(
    navController: NavHostController = rememberNavController()
) {
    val backStackEntry by navController.currentBackStackEntryAsState()
    val route = backStackEntry?.destination?.route
    val currentScreenTitle = if (route != null) {
        stringResource(BackHandlerTestScreen.valueOf(route).title)
    } else {
        "*"
    }
    val canNavigateBack = navController.previousBackStackEntry != null

    Scaffold(
        topBar = {
            BackHandlerTestAppBar(
                title = currentScreenTitle,
                canNavigateBack = canNavigateBack,
                navigateUp = {
                    navController.navigateUp()
                }
            )
        }
    ) { innerPadding ->
        NavHost(
            navController = navController,
            startDestination = BackHandlerTestScreen.Home.name,
            modifier = Modifier.padding(innerPadding)
        ) {
            composable(route = BackHandlerTestScreen.Home.name) {
                HomeScreen(
                    onClick = {
                        navController.navigate(BackHandlerTestScreen.BackButtonClickCounter.name)
                    }
                )
            }
            composable(route = BackHandlerTestScreen.BackButtonClickCounter.name) {
                BackButtonClickCounterScreen()
            }
        }
    }
}

enum class BackHandlerTestScreen(@StringRes val title: Int) {
    Home(title = R.string.app_name),
    BackButtonClickCounter(title = R.string.back_button_click_counter_title),
}

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun BackHandlerTestAppBar(
    title: String,
    canNavigateBack: Boolean,
    navigateUp: () -> Unit,
    modifier: Modifier = Modifier
) {
    TopAppBar(
        title = {
            Text(title)
        },
        colors = TopAppBarDefaults.mediumTopAppBarColors(
            containerColor = MaterialTheme.colorScheme.primaryContainer
        ),
        modifier = modifier,
        navigationIcon = {
            if (canNavigateBack) {
                IconButton(onClick = navigateUp) {
                    Icon(
                        imageVector = Icons.Filled.ArrowBack,
                        contentDescription = stringResource(R.string.back_button)
                    )
                }
            }
        }
    )
}

@Composable
fun HomeScreen(
    onClick: () -> Unit,
) {
    Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background) {
        Column(
            modifier = Modifier.fillMaxSize(),
            verticalArrangement = Arrangement.Center,
            horizontalAlignment = Alignment.CenterHorizontally
        ) {
            Text(stringResource(id = R.string.app_name))
            Button(onClick = { onClick() }) {
                Text(text = stringResource(id = R.string.back_click_counter))
            }
        }

    }
}

@Composable
fun BackButtonClickCounterScreen() {
    var backButtonClickCounter by remember { mutableIntStateOf(0) }

    BackHandler {
        backButtonClickCounter++
    }

    Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background) {
        Column(
            modifier = Modifier.fillMaxSize(),
            verticalArrangement = Arrangement.Center,
            horizontalAlignment = Alignment.CenterHorizontally
        ) {
            Text(text = stringResource(id = R.string.back_clicks_counted))
            Text(text = backButtonClickCounter.toString())
        }
    }
}

我使用的是 Android 9(API 级别 28)(这是我们需要支持的最低 API 级别,但我也在模拟器中尝试了 API 级别 33),似乎我的 BackHandler 从未被调用。我是否做错了什么或者我在 Jetpack Compose 中发现了错误?

亲切的问候,

拉尔斯

P.S.:我知道 Jetpack Compose BackHandler 在我的 Android 9 手机上不会触发

android kotlin android-jetpack-compose
1个回答
0
投票

我无法使用您提供的代码重现问题。我测试的设备是三星S24+,API 34模拟器,API 28模拟器。

以前版本的 Jetpack Navigation 似乎在 BackHandler 方面存在一些问题,因此请检查您是否使用的是最新版本。我使用的版本是2.7.7.

GIF

© www.soinside.com 2019 - 2024. All rights reserved.