标签: android-navigation-graph

Jetpack Compose Navigation - 将参数传递给 startDestination

我正在构建的应用程序使用带有路线的组合导航。挑战在于起始目的地是动态的。

这是一个最小的例子:

class MainActivity : ComponentActivity()
{
    override fun onCreate(savedInstanceState: Bundle?)
    {
        super.onCreate(savedInstanceState)

        setContent {
            val navController = rememberNavController()

            NavHost(
                navController = navController,
                startDestination = "dynamic/1", // doesn't work
                // startDestination = "static", // workaround
            ) {
                composable(
                    route = "dynamic/{$ARG_ID}",
                    arguments = listOf(navArgument(ARG_ID) { type = NavType.StringType }),
                ) {
                    val id = it.arguments?.getString(ARG_ID)
                    Text("dynamic route, received argument: $id!")
                }
                // part of the workaround
                // composable(
                //  route = "static",
                // ) {
                //  LaunchedEffect(this) {
                //      navController.navigate("dynamic/1") …
Run Code Online (Sandbox Code Playgroud)

android android-jetpack-navigation android-jetpack-compose android-navigation-graph

29
推荐指数
1
解决办法
1万
查看次数

通过 navGraphViewModels 创建 java.lang.IllegalArgumentException: NavController 的返回堆栈上没有 ID 为 <destination id> 的目标

当配置发生更改并因此重新创建我的 Activity 和 Fragment 时,我的导航图作用域 ViewModel 不可用,而 Fragments 已再次创建。
看起来 Fragment 是在 navGraph 之前重新创建的。

我使用此代码从我的片段初始化我的 navGraph 范围的 ViewModel:

private val myViewModel: MyViewModel by navGraphViewModels(R.id.nav_graph_id)
Run Code Online (Sandbox Code Playgroud)

myViewModel如果我尝试在片段函数中使用onViewCreated,我会IllegalArgumentException在配置更改后得到一个。例外情况:

java.lang.IllegalArgumentException: No destination with ID <destination id> is on the NavController's back stack
Run Code Online (Sandbox Code Playgroud)

我该如何处理这个问题?

我已经检查过我的 ID 没有在其他地方使用。

编辑1:

这是我的activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">
    
    <androidx.fragment.app.FragmentContainerView
            android:id="@+id/main_nav_host"
            android:name="androidx.navigation.fragment.NavHostFragment"
            android:layout_width="0dp"
            android:layout_height="0dp"
            app:defaultNavHost="true"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintBottom_toBottomOf="parent"
            app:navGraph="@navigation/main_nav_graph" />

</androidx.constraintlayout.widget.ConstraintLayout>
Run Code Online (Sandbox Code Playgroud)

这是我的 main_nav_graph.xml:

<navigation
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/main_nav_graph"
        app:startDestination="@id/main_nav_graph_1"> …
Run Code Online (Sandbox Code Playgroud)

android kotlin android-navigation-graph

13
推荐指数
2
解决办法
1万
查看次数

Android Navigation Instrumentation 测试抛出方法 addObserver 必须在主线程上调用

我有两个 Fragment,一个是我图中的 home 片段。单击按钮后,用户将被导航到第二个片段。它通过将用户导航到第二个片段并显示文本来按预期工作。所以图很好。

现在我想编写一个仪器测试。

@RunWith(AndroidJUnit4::class)
class TransitionTest {

    @Test
    fun testNavigationToSecondFragment() {
        
        val navController = TestNavHostController(
            ApplicationProvider.getApplicationContext())

        navController.setGraph(R.navigation.my_graph) <--throws exception

        // the rest of my test continues here
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,上面显示的用于设置图形的行会引发以下异常:

IllegalStateException:必须在主线程上调用方法 addObserver。

我的环境:

fragment_version = 1.2.5 nav_version = 2.3.1 浓缩咖啡 = 3.3.0

有谁知道发生了什么以及如何解决它?

kotlin android-espresso android-navigation-graph

12
推荐指数
2
解决办法
5312
查看次数

Handle Toolbar back button with Navigation component

I'm following single activity approach. I have navigation toolbar, whenever i go to other screens (fragments) instead of hamburger icon i will have back arrow.

What i want to achieve is, pop my current fragment using action on pressing toolbar back arrow.

I've tried

requireActivity().getOnBackPressedDispatcher().addCallback(this, new OnBackPressedCallback(true) {
    @Override
    public void handleOnBackPressed() {
        NavHostFragment.findNavController(EventDetailsFragment.this)
        .navigate(R.id.action_nav_event_details_to_nav_home);
    }
});
Run Code Online (Sandbox Code Playgroud)

But not getting the call over there, i checked by running app in debug mode.

android android-toolbar android-mvvm android-navigation-graph

11
推荐指数
2
解决办法
7780
查看次数

使用导航组件将参数安全地传递给嵌套图

我正在使用 Android Jetpack 导航组件。我有一个带有 id 的嵌套导航图,比如说嵌套图R.id.nested_graph 的第一个Fragment接收一个参数。

<navigation
        android:id="@+id/nested_graph"
        android:label="Nested Graph"
        app:startDestination="@id/firstFragment">
        <fragment
            android:id="@+id/firstFragment"
            android:name="...."
            android:label="....">
            <argument
                android:name="item_id"
                app:argType="integer" />
        </fragment>
        [...]
    </navigation>
Run Code Online (Sandbox Code Playgroud)

如何使用安全 args将参数传递给嵌套图?

目前,我需要在包中手动传递参数,使用直接接收嵌套图的 id 的 API:

        val args = Bundle()
        args.putInt("item_id", itemId)
        navController.navigate(R.id.nested_graph, args)
Run Code Online (Sandbox Code Playgroud)

我想使用安全参数,并执行以下操作:

        val directions = OrigininFragmentDirections.nestedGraph(itemId)
        navController.navigate(directions)
Run Code Online (Sandbox Code Playgroud)

但是在尝试时,我在构建时收到以下错误:

Too many arguments for public final fun nestedGraph(): NavDirections defined 
Run Code Online (Sandbox Code Playgroud)

问题是导航图预处理正在生成工厂方法来创建没有签名中所需参数的NavDirections对象。

嵌套图的声明如下所示:

android android-navigation android-jetpack-navigation android-navigation-graph

11
推荐指数
2
解决办法
3654
查看次数

使用 navGraphViewModels 访问子 NavHostFragment 的图形范围的 ViewModel

我正在使用 Android Jetpack (2.2.0-alpha01) 的导航组件。

我希望使用嵌套在我的主 NavHostFragment 中的子 NavHostFragment,它配备了自己的子导航图。请查看以下图片了解上下文:

在此处输入图片说明

子导航主机在位于 MainNavHost 堆栈前端的片段中定义如下:

<fragment
    android:id="@+id/childNavHostFragment"
    android:name="androidx.navigation.fragment.NavHostFragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:defaultNavHost="false"
    app:navGraph="@navigation/child_graph" />
Run Code Online (Sandbox Code Playgroud)

在 CHILD Nav Host Fragment 前面的片段中,我尝试使用以下代码将 ViewModel 范围限定为 R.navigation.child_graph:

private val childGraphScopedViewModel: ChildGraphScopedViewModel by navGraphViewModels(R.navigation.child_graph) {
    viewModelFactory
}
Run Code Online (Sandbox Code Playgroud)

访问 childGraphScopedViewModel 时,我收到错误消息崩溃:

java.lang.IllegalArgumentException: No NavGraph with ID 2131689472 is on the NavController's back stack.
Run Code Online (Sandbox Code Playgroud)

我相信懒惰的 init 调用by navGraphViewModel()是在 mainGraph 中寻找导航图。

如何访问子 navHostFragment 范围的 ViewModel?感谢您的时间。

android viewmodel kotlin android-architecture-navigation android-navigation-graph

10
推荐指数
2
解决办法
4716
查看次数

BottomSheetDialogFragment 中的 NavigationComponent 导航

Android 的导航组件能否用于在 BottomSheet 内导航(即在单个底部工作表中替换/添加片段)?

我知道如何BottomSheetDialogFragment使用<dialog>导航图中的标签启动一个。例如,下面的代码nav_graph.xml允许用户从一个BottomSheetDialogFragment(fragmentOne)导航到另一个BottomSheetDialogFragment(fragmentTwo)。FragmentTwo 作为第二个BottomSheet 打开,位于FragmentOne 的BottomSheet 之上。

但是,如果我想让 fragmentTwo 替换同一个 BottomSheet 中的 fragmentOne 怎么办?我将如何使用导航图完成此操作?

<navigation android:id="@+id/nav_graph"
        app:startDestination="@id/fragmentOne">

    <dialog android:id="@+id/fragmentOne"
        android:name="com.example.navcomponentapp.FragmentOne"
        android:label="fragment_fragment_one"
        tools:layout="@layout/fragment_fragment_one">

        <action android:id="@+id/action_fragmentOne_to_fragmentTwo2"
            app:destination="@id/fragmentTwo"/>
    </dialog>

    <dialog android:id="@+id/fragmentTwo"
        android:name="com.example.navcomponentapp.FragmentTwo"
        android:label="fragment_fragment_two"
        tools:layout="@layout/fragment_fragment_two"/>
</navigation>
Run Code Online (Sandbox Code Playgroud)

演示(这不是我想要的。我不想在另一个bottomSheet上打开一个bottomSheet

android android-navigation android-architecture-components android-jetpack android-navigation-graph

9
推荐指数
1
解决办法
1915
查看次数

为什么Android Navigation Component 屏幕不返回上一个Fragment,而是调用了previos Fragment 的onViewCreated 中的一个方法?

我有2个片段通话CreateRoomFragmentDisplayPhotoFragment,导航图是这个样子的:

<navigation>    
<fragment
    android:id="@+id/createRoomFragment"
    android:name="package.room.CreateRoomFragment"
    android:label="Create a room"
    tools:layout="@layout/fragment_create_room">
    <action
        android:id="@+id/action_createRoomFragment_to_roomFragment"
        app:destination="@id/roomFragment" />
    <action
        android:id="@+id/action_createRoomFragment_to_displayPhotoFragment"
        app:destination="@id/displayPhotoFragment" />
</fragment>

<fragment
    android:id="@+id/displayPhotoFragment"
    android:name="package.fragment.DisplayPhotoFragment"
    android:label="fragment_display_photo"
    tools:layout="@layout/fragment_display_photo" >
    <argument android:name="bitmap"
              app:argType="android.graphics.Bitmap"/>
</fragment>
Run Code Online (Sandbox Code Playgroud)

所以当我想从 to 移动CreateRoomFragmentDisplayPhotoFragment,我使用如下 do:

NavDirections action = CreateRoomFragmentDirections.actionCreateRoomFragmentToDisplayPhotoFragment(selectedPhoto);
Navigation.findNavController(view).navigate(action);
Run Code Online (Sandbox Code Playgroud)

这样做,我可以导航到DisplayPhotoFragment.

但是当我按下back设备的按钮以及Back arrow工具栏中的 时,它无法返回到CreateRoomFragment

我试过这个,但仍然无法回到上一个片段:

requireActivity().getOnBackPressedDispatcher().addCallback(getViewLifecycleOwner(),
                new OnBackPressedCallback(true) {
                    @Override
                    public void handleOnBackPressed() {

                       navController.navigateUp();  //I tried this 
                       navController.popBackStack(R.id.createRoomFragment,false); //and also this
                    }
                });
Run Code Online (Sandbox Code Playgroud)

现在主要问题:

使用上面的代码,屏幕没有回到之前的Fragment( …

android android-fragments android-navigation android-architecture-navigation android-navigation-graph

9
推荐指数
2
解决办法
1万
查看次数

异常:视图没有设置 navController

当我使用 navController = Navigation.findNAvController(view) 时,我让它在活动中的标签片段中托管的片段中,应用程序因错误而崩溃:View 没有设置 navController。

这是 nav_graph:

<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/nav_graph"
    app:startDestination="@id/mainFragment">

    <fragment
        android:id="@+id/mainFragment"
        android:name="studio.apptick.mouj.view.fragments.MainFragment"
        tools:layout="@layout/fragment_main"
        android:label="fragment_main" >
        <action
            android:id="@+id/action_mainFragment_to_playlistActivityFragment"
            app:destination="@id/playlistActivityFragment" />
        <action
            android:id="@+id/action_mainFragment_to_searchActivity"
            app:destination="@id/searchActivity" />
    </fragment>
    <activity
        android:id="@+id/searchActivity"
        android:name="studio.apptick.mouj.view.activity.SearchActivity"
        android:label="activity_search"
        tools:layout="@layout/activity_search" />
</navigation>
Run Code Online (Sandbox Code Playgroud)

这是活动中的片段标签:

        android:id="@+id/nav_host_fragment"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toTopOf="@id/view_player"
        android:name="androidx.navigation.fragment.NavHostFragment"
        app:defaultNavHost="true"
        app:navGraph="@navigation/nav_graph">
    </fragment>
Run Code Online (Sandbox Code Playgroud)

navigation android navigationcontroller android-studio android-navigation-graph

8
推荐指数
3
解决办法
1万
查看次数

为什么 onViewCreated 在使用导航组件的 android 应用程序中被调用两次

我有一个简单的应用程序,其中包含一个活动和大约 4 个片段。我正在使用 android 导航组件。每次更改片段时,从我的飞溅片段开始到下一个片段, OnCreateview 和 onViewCreated 被调用两次,一次是最初创建片段时,第二次是我使用findnavController.navigate(). 我不知道为什么它会被调用两次,任何人都可以说明原因。这是我的飞溅课。

class SplashFragment : Fragment(), SocketConnection.SocketCallbacks {

    lateinit var binding: SplashFragmentBinding


    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        Timber.d("on View created")
        SocketConnection.getInstance.socketConnectionListener(this)

    }


    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        Timber.d("on create view")
        binding = DataBindingUtil.inflate(inflater, R.layout.fragment_splash, container, false)
        return binding.root
    }

    override fun onResume() {
        super.onResume()
        Timber.d("On resume")
        activity?.setupBackButton(false)
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        Timber.d("On create")
        setHasOptionsMenu(false)
    }
    
    override …
Run Code Online (Sandbox Code Playgroud)

android android-architecture-navigation android-navigation-graph

8
推荐指数
2
解决办法
1566
查看次数