Android 在MainActivity内的导航主机片段上调用方法

Android 在MainActivity内的导航主机片段上调用方法,android,android-fragments,android-jetpack,android-jetpack-navigation,Android,Android Fragments,Android Jetpack,Android Jetpack Navigation,我正在开发我的第一个Android应用程序,我知道架构可能有点混乱。 我正在android中使用新的Jetpack导航。我有一个导航抽屉,我在其中添加了一个回收器视图,用户可以从中选择回收器视图中的项目,并根据主导航主机片段滚动到特定位置 我想知道如何在与导航主机片段关联的底层片段中调用方法。我可以获得导航主机片段的句柄,但我想在该特定片段中调用一个自定义方法,该片段没有通过导航主机片段公开,因此它会给我编译时错误 我使用的方法如下 val readerFragment: ReaderFragm

我正在开发我的第一个Android应用程序,我知道架构可能有点混乱。 我正在android中使用新的Jetpack导航。我有一个导航抽屉,我在其中添加了一个回收器视图,用户可以从中选择回收器视图中的项目,并根据主导航主机片段滚动到特定位置

我想知道如何在与导航主机片段关联的底层片段中调用方法。我可以获得导航主机片段的句柄,但我想在该特定片段中调用一个自定义方法,该片段没有通过导航主机片段公开,因此它会给我编译时错误

我使用的方法如下

val readerFragment: ReaderFragment = supportFragmentManager.findFragmentById(R.id.reader_fragment) as ReaderFragment
readerFragment.scrollToChapter(5)

这里,Reader fragment是导航主机片段下使用的实际片段,这导致以下异常

com.example.quran E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.quran, PID: 7640
    kotlin.TypeCastException: null cannot be cast to non-null type com.example.quran.ReaderFragment
或者像这样直接从nav_主机_片段中获取

val readerFragment: ReaderFragment = nav_host_fragment as ReaderFragment
然后我得到以下异常

java.lang.ClassCastException: androidx.navigation.fragment.NavHostFragment cannot be cast to com.example.quran.ReaderFragment
有人能帮我从MainActivity中的nav_host_片段中获取实际片段吗

下面是导航图的代码

<?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/nav_graph"
    app:startDestination="@id/reader_fragment">
    <fragment
        android:id="@+id/reader_fragment"
        android:name="com.example.quran.ReaderFragment"
        android:label="Reader"
        tools:layout="@layout/reader_fragment">
    </fragment>
    <fragment
        android:id="@+id/chapterDetailsFragment"
        android:name="com.example.quran.ChapterDetailsFragment"
        android:label="fragment_chapter_details"
        tools:layout="@layout/fragment_chapter_details" />
</navigation>

这是主要活动的布局

<?xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.widget.DrawerLayout 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/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    tools:context=".MainActivity"
    tools:openDrawer="start">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <androidx.appcompat.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@color/colorTopNavigation">

            <TextView
                android:id="@+id/toolbar_textView"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:fontFamily="@font/montserratbold"
                android:textColor="@color/toolbarItemColor"
                android:layout_marginRight="?android:attr/actionBarSize"
                android:gravity="center"
                android:textSize="30dp"
                android:textStyle="bold" />

        </androidx.appcompat.widget.Toolbar>

        <fragment
            android:id="@+id/nav_host_fragment"
            android:name="androidx.navigation.fragment.NavHostFragment"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:defaultNavHost="true"
            app:navGraph="@navigation/nav_graph" />
    </LinearLayout>

    <com.google.android.material.navigation.NavigationView
        android:id="@+id/nav_view"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:fitsSystemWindows="true">


        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/chapters_recycler_view"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />

    </com.google.android.material.navigation.NavigationView>


</androidx.drawerlayout.widget.DrawerLayout>

解释您的问题

代码中的第一个错误:

 val readerFragment: ReaderFragment = nav_host_fragment as ReaderFragment
因为NavHostFragment是一个主机(即,您的片段在其中),所以您不能将NavHostFragment强制转换为其他任何内容

 supportFragmentManager.findFragmentById(R.id.reader_fragment) as ReaderFragment
TypeCastException:null不能转换为非null类型

findFragmentById返回null,因为它找不到您的片段。这是第二个错误


解决方案

您可以稍微修改一下以获得屏幕上的片段:

NavHostFragment navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host);
navHostFragment.getChildFragmentManager().getFragments().get(0);
您还可以检查子片段管理器,因为您的片段是nav主机的子片段:

NavHostFragment fragment = supportFragmentManager.findFragmentById(R.id.nav_host);
MyFragment frag = (MyFragment) fragment.getChildFragmentManager().findFragmentByTag(tag);
参考:


NavHostFragment是一个主机(即,您的片段在其中),因此您不能将NavHostFragment强制转换为任何其他内容。
findFragmentById
返回
null
,因为它找不到您的片段。您从何处获得活动的
supportFragmentManager
?活动中有supportFragmentManager,但似乎无法找到片段,因为它没有直接添加到活动中。或者有没有更好的方法实现相同的行为。这不是最好的方法,但是的:至少对我来说是这样。如果你把它作为一个答案,我可以接受。要按标签查找片段,我把标签放在导航组件的哪里?