所以我有两个选项卡,选项卡 A 和选项卡 B。每个选项卡都有自己的后堆栈。我使用此谷歌文档中的代码实现了多个返回堆栈导航
val navController = rememberNavController()
Scaffold(
bottomBar = {
BottomNavigation {
val navBackStackEntry by navController.currentBackStackEntryAsState()
val currentDestination = navBackStackEntry?.destination
items.forEach { screen ->
BottomNavigationItem(
icon = { Icon(Icons.Filled.Favorite, contentDescription = null) },
label = { Text(stringResource(screen.resourceId)) },
selected = currentDestination?.hierarchy?.any { it.route == screen.route } == true,
onClick = {
navController.navigate(screen.route) {
// Pop up to the start destination of the graph to
// avoid building up a large stack of destinations
// on the …Run Code Online (Sandbox Code Playgroud) android kotlin android-jetpack-navigation android-jetpack-compose jetpack-compose-navigation
我正在尝试通过 ViewModel 中的codeGitHub Oauth API获取. 我的可组合屏幕配置:playground://gh?code=XYZsavedStateHandler
NavGraphBuilder.composable(
route = "login",
deepLinks = listOf(navDeepLink {
uriPattern = "playground://gh?code={code}"
})
) {
Log.d("MyLog", it.arguments?.getString("code", "nothing") ?: "null")
//...
}
Run Code Online (Sandbox Code Playgroud)
MyLog总是nothing
我也尝试实现该NavGraphBuilder.composable.arguments参数,但结果是一样的。
我刚刚熟悉 Compose 并完成了 Google Code 实验室。https://developer.android.com/codelabs/jetpack-compose-navigation#4 - 这按预期工作,但问题是需要参数。
我还有一个需要 URL 并且可以工作的 WebViewScreen 可组合项。
builder.composable(
route = "browser",
arguments = listOf(
navArgument("url") {
type = NavType.StringType
}
),
deepLinks = listOf(
navDeepLink {
uriPattern = "playground://gh/browser/{url}"
}
)
) {
//...
}
Run Code Online (Sandbox Code Playgroud)
不确定这是否可以通过 …
我正在努力使用 Jetpack Compose 导航。我遵循 NowInAndroid 架构,但没有正确的行为。我的底部栏中有 4 个目的地,其中之一是 Feed 类型的目的地。在本例中,它调用 Firebase 数据库来获取多个产品。问题是,每次我更改目标(ej -> SearchScreen)并返回到 Feed 时,该(Feed)都不会恢复并再次加载所有数据。有人知道发生了什么事吗?
这是我的 navigationTo 函数 ->
fun navigateToBottomBarRoute(route: String) {
val topLevelOptions = navOptions {
popUpTo(navController.graph.findStartDestination().id) {
saveState = true
}
launchSingleTop = true
restoreState = true
}
when (route) {
HomeSections.FEED.route -> navController.navigateToFeed(navOptions = topLevelOptions)
HomeSections.SEARCH.route -> navController.navigateToSearch(navOptions = topLevelOptions)
else -> {}
}
}
Run Code Online (Sandbox Code Playgroud)
我的提要屏幕 ->
@OptIn(ExperimentalLifecycleComposeApi::class)
@Composable
fun Feed(
onProductClick: (Long, String) -> Unit,
onNavigateTo: (String) -> Unit,
modifier: Modifier = Modifier,
viewModel: …Run Code Online (Sandbox Code Playgroud) android kotlin android-jetpack-compose kotlin-stateflow jetpack-compose-navigation
这是导致无限重组问题的代码
主要活动
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
val navController = rememberNavController()
val viewModel : MainViewModel by viewModel()
val state by viewModel.state.observeAsState()
NavHost(navController = navController, startDestination = "firstScreen") {
composable("firstScreen") { FirstScreen(
navigate = {
navController.navigate("secondScreen")
}, updateState = {
viewModel.getState()
},
state
)}
composable("secondScreen") { SecondScreen() }
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
视图模型
class MainViewModel : ViewModel() {
//var state = MutableStateFlow(0)
private val _state = MutableLiveData(0)
val state: LiveData<Int> = _state
fun …Run Code Online (Sandbox Code Playgroud) android kotlin android-jetpack-compose jetpack-compose-navigation compose-recomposition
我想在顶部栏中向我的应用程序添加一个字符串资源,但是当我调用它时会出现一个数字,并且因为它是一个密封类,所以它不允许我实现stringResource或getString。
<resources>
<string name="app_name">AppEsquema</string>
<string name="app"><b>"Translator</b>"</string>
</resources>
Run Code Online (Sandbox Code Playgroud)
sealed class Destinations(
val route: String,
val title: String,
val icon: ImageVector
){
//Bottom bar windows
object Translate: Destinations(R.string.app.toString(), "Translate", Icons.Default.Translate)
object Words: Destinations("Words", "Words", Icons.Default.Assignment)
object Numbers: Destinations("Numbers", "Numbers", Icons.Default.FormatListNumbered)
}
Run Code Online (Sandbox Code Playgroud)
我不直接输入字符串,因为顶部栏在浏览窗口时会更改名称,并且我希望它能够个性化。
这是通过窗口更改标题的代码,如果它有效,但它获取窗口路径的名称,我看到的唯一解决方案是将字符串资源分配给路径来自定义它。
resources android kotlin android-jetpack-compose jetpack-compose-navigation
我遇到了这样的要求:当用户通过后退导航流程返回时,我必须执行某些任务。
假设:当前用户位于 A 屏幕上,单击按钮后导航到 B 屏幕。在 B 屏幕上,我正在BackHandler使用此代码将用户导航到后屏幕,navController.navigateUp()因为此代码可以完美地将用户导航到后屏幕。
但我无法确定用户是通过后退导航还是初始启动流程来的。
已经尝试过的解决方案: val isFromBackNavigation = parentNavController.currentBackStackEntryAsState().value?.destination?.route == AppNav.Wishlist.route
对于初始启动,这也会返回 true。
在 Android 中,我经常想要导航以响应 ViewModel 的状态更改。(例如,成功的身份验证会触发导航到用户的主屏幕。)
最佳实践是从 ViewModel 内触发导航吗?是否有有意的机制来触发可组合项中的导航以响应 ViewModel 状态更改?
使用 Jetpack Compose 处理此用例的过程并不明显。如果我尝试类似以下示例的操作,将会发生导航,但我导航到的目的地将无法正常运行。我相信这是因为在调用导航之前不允许完成原始的可组合函数。
// Does not behave correctly.
@Composable fun AuthScreen() {
val screenState = viewModel.screenState.observeAsState()
if(screenState.value is ScreenState.UserAuthenticated){
navController.navigate("/gameScreen")
} else {
LoginScreen()
}
}
Run Code Online (Sandbox Code Playgroud)
如果我使用 LaunchedEffect ,我确实会观察到正确的行为,如下所示:
// Does behave correctly.
@Composable fun AuthScreen() {
val screenState = viewModel.screenState.observeAsState()
if(screenState.value is ScreenState.UserAuthenticated){
LaunchedEffect(key1 = "test") {
navController.navigate("$/gameScreen")
}
} else {
LoginScreen()
}
}
Run Code Online (Sandbox Code Playgroud)
它是否正确?LaunchedEffect 的文档说明如下,但我并不是 100% 清楚其含义:
当 LaunchedEffect 进入组合时,它将启动块到组合的 CoroutineContext 中。当 LaunchedEffect 用不同的 key1、key2 或 …
android android-jetpack-compose jetpack-compose-navigation compose-recomposition
我的应用程序使用 hilt,我LoadManager在活动内部进行了一些工作,使用读取联系人ContentResolver,当我完成工作时,我得到发送到我的 viewModel 的光标,以便处理数据并执行一些业务逻辑,为此我声明了以下内容在我的活动之上:
@AndroidEntryPoint
class MainActivity : ComponentActivity(), LoaderManager.LoaderCallbacks<Cursor> {
private val contactsViewModel: ContactsViewModel by viewModels()
...
Run Code Online (Sandbox Code Playgroud)
这样我就可以在里面使用它onLoadFinished :
override fun onLoadFinished(loader: Loader<Cursor>, cursor: Cursor?) {
contactsViewModel.updateContactsListFromCursor(cursor, loader.id)
}
Run Code Online (Sandbox Code Playgroud)
在我的 viewModel 中,我有以下代码,它使用要显示的联系人更新列表的 ui 状态:
data class ContactsListUiState(
val contacts: MutableList<Contact>,
val searchFilter: String)
@HiltViewModel
class ContactsViewModel @Inject constructor() : ViewModel() {
private val _contactsListUiState =
MutableStateFlow(ContactsListUiState(mutableStateListOf(), ""))
val contactsListUiState: StateFlow<ContactsListUiState> = _contactsListUiState.asStateFlow()
private fun updateContactsList(filter: String) {
viewModelScope.launch(Dispatchers.IO) {
...
_contactsListUiState.update { currentState -> …Run Code Online (Sandbox Code Playgroud) android android-viewmodel android-jetpack-compose dagger-hilt jetpack-compose-navigation
在测试我的应用程序时,我意识到如果用户FloatingActionButton快速按下几次,onClick 回调可能会被多次触发。就我而言,这导致返回堆栈被多次弹出,因为onPopBackStack回调会冒泡到NavHost它可以访问navController并调用该popBackStack方法的位置。
fun AddEditTodoScreen(onPopBackStack: () -> Unit, viewModel: AddEditTodoViewModel = viewModel()) {
var isNavigating by remember{
mutableStateOf(false)
}
LaunchedEffect(key1 = true){
viewModel.uiEvent.collect{event : UiEvent ->
when(event){
is UiEvent.PopBackStack -> onPopBackStack
else -> Unit
}
}
}
Scaffold(floatingActionButton = {
FloatingActionButton(onClick = {
if(!isNavigating){
isNavigating = !isNavigating
onPopBackStack()
}
}) {
Icon(imageVector = Icons.Default.Check, contentDescription = "Check")
}
Run Code Online (Sandbox Code Playgroud)
目前,我只是在第一次单击isNavigating时将 a 设置为 true FloatingActionButton,如果再次单击,它会检查该isNavigating标志是否设置为 true,如果是,则不执行任何操作。如果有的话,有什么更好的方法来解决这个问题?
我想从通知操作按钮导航到撰写中的单个活动应用程序中的特定屏幕。根据此文档,我决定使用深层链接导航。问题是,当我单击通知操作按钮时,它会在导航到预期屏幕之前重新启动我的活动。如果我的活动在后台打开,我不希望它重新启动。
我就是这样做的:
这是我在应用程序清单中指定的内容:
<activity
android:name=".ui.AppActivity"
android:launchMode="standard"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="myApp" android:host="screenRoute" />
</intent-filter>
</activity>
Run Code Online (Sandbox Code Playgroud)
这是我的根导航图中的深层链接声明:
composable(
route = "screenRoute",
deepLinks = listOf(navDeepLink { uriPattern = "myApp://screenRoute" })
) {
ComposableScreen()
}
Run Code Online (Sandbox Code Playgroud)
这是我用于通知操作按钮的待处理意图:
val intent = Intent().apply {
action = Intent.ACTION_VIEW
data = "myApp://screenRoute".toUri()
}
val deepLinkPendingIntent = TaskStackBuilder.create(context).run {
addNextIntentWithParentStack(intent)
getPendingIntent(1234, FLAG_UPDATE_CURRENT)
}
Run Code Online (Sandbox Code Playgroud)
我以为我在这里做错了什么,因为我没有找到任何关于这次重启的信息。因此,我下载了使用深层链接的官方撰写导航代码实验室(因为它也是单个应用程序活动),并且在使用来自意图的深层链接时执行相同的操作,活动将重新启动。
所以我的问题是: