4

我的目标是通过复杂的导航架构(我想)以最佳方式理解和使用导航组件。

为了制作全局上下文,我使用了一个包含 5 个项目的主 BottomNavigationBar。对于碎片关联的管理,我使用谷歌给出的示例:https ://github.com/googlesamples/android-architecture-components/tree/master/NavigationAdvancedSample 。

但我的情况比底栏要复杂一些。在底部栏启动的片段之一的目的地之一中,我有另一个 RecyclerView 菜单和一个片段容器,用于在片段之间导航。我把我的主要图表的重要部分放在这里:

<?xml version="1.0" encoding="utf-8"?>
<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"
    app:startDestination="@id/mainFragment">
    <fragment
        android:id="@+id/mainFragment"
        android:name="com.exemple.fragment.MainFragment"
        android:label="@string/main_label"
        tools:layout="@layout/mainFragment">
        <action
            android:id="@+id/action_mainFragment_to_goScreen"
            app:destination="@id/goScreen">
        </action>
    </fragment>
    <fragment
        android:id="@+id/goScreen"
        android:name="com.exemple.fragment.GoFragment"
        android:label="@string/goLabel"
        tools:layout="@layout/fragment_go">
        <action
            android:id="@+id/action_goScreen_to_mainFragment"
            app:destination="@id/mainFragment" />
        <argument
            android:name="arg1"
            app:argType="com.exemple.customType"
            android:defaultValue="@null"
            app:nullable="true" />
        <argument
            android:name="arg2"
            app:argType="string"
            android:defaultValue="@null"
            app:nullable="true" />
    </fragment>
</navigation>

以及带有底部栏的 xml 开始此图:

<?xml version="1.0" encoding="utf-8"?>
<layout 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"
    tools:context="com.exemple.MainActivity">

    <RelativeLayout
        android:id="@+id/constraintLayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <androidx.appcompat.widget.Toolbar
            android:id="@+id/fake_toolbar"
            android:layout_width="0dp"
            android:layout_height="0dp"/>

        <androidx.fragment.app.FragmentTabHost
            android:id="@+id/main_host_container"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_above="@+id/bottom_navigation" />

        <!-- navigation bottom -->
        <com.google.android.material.bottomnavigation.BottomNavigationView
            android:id="@+id/bottom_navigation"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="start"
            android:layout_alignParentBottom="true"
            android:background="@color/navigationBarColor"
            app:itemIconTint="@color/textColorNavigationBar"
            app:itemTextColor="@color/textColorNavigationBar"
            app:menu="@menu/menu_bottom_navigation" />
    </RelativeLayout>
</layout>

这是与 go 片段(目标)对应的图示例:

<?xml version="1.0" encoding="utf-8"?>
<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/go"
    app:startDestination="@id/firstGoFragment">

    <action android:id="@+id/action_to_firstGoFragment"
        app:destination="@id/firstGoFragment"/>
    <fragment
        android:id="@+id/firstGoFragment"
        android:name="com.exemple.go.firstGoFragment"
        android:label="@string/firstGoFragmentLabel"
        tools:layout="@layout/firstGoFragment" >
    </fragment>

    <action android:id="@+id/action_to_secondFragment"
    app:destination="@id/secondFragment"/>
    <fragment
        android:id="@+id/secondFragment"
        android:name="com.exemple.go.SecondFragment"
        android:label="@string/secondFragmentLabel"
        tools:layout="@layout/secondFragment" >
    </fragment>
</navigation>

关联xml是:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:tools="http://schemas.android.com/tools"
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@color/colorGreyLight"
        android:clickable="true"
        android:focusable="true">

        <RelativeLayout
            android:id="@+id/linearLayout3"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="@color/colorPrimary"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent">

            <androidx.appcompat.widget.AppCompatImageView
                android:id="@+id/quit"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerVertical="true"
                android:layout_marginStart="16dp"
                android:paddingBottom="15dp"
                android:paddingEnd="15dp"
                android:paddingTop="15dp"
                app:srcCompat="@drawable/ic_quit_white" />

            <com.teedji.mobeelity.custom.CustomTextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerInParent="true"
                android:text="@string/go"
                android:textColor="@color/colorWhite"
                android:textSize="17sp"
                android:textStyle="bold" />

        </RelativeLayout>

        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/goMenu"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:background="@color/colorWhite"
            android:overScrollMode="never"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintHorizontal_bias="1.0"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/linearLayout3" />

        <!-- include fragment child container -->
        <fragment
            android:id="@+id/go_nav_host_fragment_container"
            android:name="androidx.navigation.fragment.NavHostFragment"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:layout_marginTop="0dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/goMenu"
            app:navGraph="@navigation/go"/>
    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

现在,要导航到 go 屏幕,我只需使用

findNavController().navigate(MainFragmentDirections.actionMainFragmentToGoScreen(arg1, arg2))

或者

findNavController().navigate(R.id. action_mainFragment_to_goScreen)

但是当我在 Go 片段上时,我发现使用findNavController()的 navController 仍然是 mainFragment 之一。所以navigate()函数没有找到动作ID。为了解决这个问题,我不得不像这样在 GoFragment 中以编程方式更改 navHost:

override fun onCreate(savedInstanceState: Bundle?) {
        Log.i(LOG_TAG, "onCreate")
        super.onCreate(savedInstanceState)
        if( fragmentManager != null ) {
            // If the Nav Host fragment exists, return it
            val existingFragment = fragmentManager!!.findFragmentByTag(FRAGMENT_TAG) as NavHostFragment?
            existingFragment?.let { navHostGoFragment = it }

            // Otherwise, create it and return it.
            if ( navHostGoFragment == null) {
                navHostGoFragment = NavHostFragment.create(R.navigation.go)
                fragmentManager!!.beginTransaction()
                        .add(R.id.go_nav_host_fragment_container, navHostGoFragment!!, FRAGMENT_TAG)
                        .commit()
            }
        }else {
            Log.e(LOG_TAG, "fragmentManager is null so I can't find the fragment host")
        }
}

然后用于navHostGoFragment!!.navController.navigate(R.id.action_to_firstGoFragment)在新容器中导航但是这样做,我的 firstFragment 被创建了两次(我可以在我的日志中看到它)并且会产生一些问题Cannot add the same observer with different lifecycles,例如(我通过添加来解决这个问题

if  (model.getLiveData().hasObservers()) {
        model.getLiveData().removeObserver(observer)
    }

model.getLiveData().observe(viewLifecycleOwner, observer)

)但我认为我没有像我应该做的那样做导航部分......

您能否提供任何帮助以使这项工作更有效且稳定?

4

1 回答 1

1

go_nav_host_fragment_container.findNavController().navigate()如果您正在使用 Kotlin Android Extensions 或,请尝试使用,findViewById(R.id.go_nav_host_fragment_container).findNavController().navigate()看看它是否有效。

于 2019-10-02T23:45:47.123 回答