【问题标题】:Navigation with Fragment that takes a parameter使用带有参数的 Fragment 进行导航
【发布时间】:2020-09-19 12:28:21
【问题描述】:

我的应用程序包含一个ViewPager,其中包含相同类型的9 Fragments。这个 Fragment 在声明时在其构造函数中接受一个参数,如下所示。

NewsFragment.kt

class NewsFragment(section: NewsSection) : Fragment() {
   //...
}

CategoryFragmentPagerAdapter.kt

class CategoryFragmentPagerAdapter(fm: FragmentManager)
    : FragmentPagerAdapter(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {

    override fun getItem(position: Int): Fragment =
        NewsFragment(NewsSection.getItem(position))

    override fun getCount(): Int = NewsSection.values().size

    override fun getPageTitle(position: Int): CharSequence =
         NewsSection.getItem(position).sectionName

}

这个片段包含一些动作,应该将用户导航到其他片段。

我尝试使用Jetpack Navigation Component 方法实现导航,但看起来它给出了错误,因为导航图不能接受带参数的片段。

关于在这种情况下如何实现Navigation 有什么想法吗?

编辑


这是我在活动的XML layout中的FragmentContainerView

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

这就是我在活动中实现navController 的方式

override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        
        setupDataBinding()
        val navHostFragment = supportFragmentManager.findFragmentById(R.id.fragment_container) as NavHostFragment
        val navController = navHostFragment.navController
}

我没有再添加任何配置,这是我运行应用时弹出的error

java.lang.RuntimeException: Unable to start activity ComponentInfo{com.domain.news/com.domain.news.ui.activities.MainActivity}: android.view.InflateException: Binary XML file line #18 in com.domain.news:layout/activity_main: Binary XML file line #22 in com.domain.news:layout/content_main: Error inflating class androidx.fragment.app.FragmentContainerView
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3307)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3446)
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83)
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2043)
        at android.os.Handler.dispatchMessage(Handler.java:107)
        at android.os.Looper.loop(Looper.java:224)
        at android.app.ActivityThread.main(ActivityThread.java:7548)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:539)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:950)
     Caused by: android.view.InflateException: Binary XML file line #18 in com.domain.news:layout/activity_main: Binary XML file line #22 in com.domain.news:layout/content_main: Error inflating class androidx.fragment.app.FragmentContainerView
     Caused by: android.view.InflateException: Binary XML file line #22 in com.domain.news:layout/content_main: Error inflating class androidx.fragment.app.FragmentContainerView
     Caused by: androidx.fragment.app.Fragment$InstantiationException: Unable to instantiate fragment com.domain.news.ui.fragments.news.NewsFragment: could not find Fragment constructor
        at androidx.fragment.app.Fragment.instantiate(Fragment.java:563)
        at androidx.fragment.app.FragmentContainer.instantiate(FragmentContainer.java:57)
        at androidx.fragment.app.FragmentManager$3.instantiate(FragmentManager.java:390)
        at androidx.navigation.fragment.FragmentNavigator.instantiateFragment(FragmentNavigator.java:132)
        at androidx.navigation.fragment.FragmentNavigator.navigate(FragmentNavigator.java:162)
        at androidx.navigation.fragment.FragmentNavigator.navigate(FragmentNavigator.java:58)
        at androidx.navigation.NavGraphNavigator.navigate(NavGraphNavigator.java:71)
        at androidx.navigation.NavGraphNavigator.navigate(NavGraphNavigator.java:28)
        at androidx.navigation.NavController.navigate(NavController.java:1049)
        at androidx.navigation.NavController.onGraphCreated(NavController.java:633)
        at androidx.navigation.NavController.setGraph(NavController.java:586)
        at androidx.navigation.NavController.setGraph(NavController.java:551)
        at androidx.navigation.NavController.setGraph(NavController.java:533)
        at androidx.navigation.fragment.NavHostFragment.onCreate(NavHostFragment.java:238)
        at androidx.fragment.app.Fragment.performCreate(Fragment.java:2684)
        at androidx.fragment.app.FragmentStateManager.create(FragmentStateManager.java:280)
        at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1175)
        at androidx.fragment.app.FragmentManager.addAddedFragments(FragmentManager.java:2224)
        at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:1997)
        at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:1953)
        at androidx.fragment.app.FragmentManager.execSingleAction(FragmentManager.java:1818)
        at androidx.fragment.app.BackStackRecord.commitNowAllowingStateLoss(BackStackRecord.java:303)
        at androidx.fragment.app.FragmentContainerView.<init>(FragmentContainerView.java:166)
        at androidx.fragment.app.FragmentLayoutInflaterFactory.onCreateView(FragmentLayoutInflaterFactory.java:51)
2020-09-19 20:39:22.012 16179-16179/com.domain.news E/AndroidRuntime:     at androidx.fragment.app.FragmentController.onCreateView(FragmentController.java:135)
        at androidx.fragment.app.FragmentActivity.dispatchFragmentsOnCreateView(FragmentActivity.java:356)
        at androidx.fragment.app.FragmentActivity.onCreateView(FragmentActivity.java:335)
        at android.view.LayoutInflater.tryCreateView(LayoutInflater.java:1073)
        at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:1001)
        at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:965)
        at android.view.LayoutInflater.rInflate(LayoutInflater.java:1127)
        at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:1088)
        at android.view.LayoutInflater.rInflate(LayoutInflater.java:1130)
        at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:1088)
        at android.view.LayoutInflater.parseInclude(LayoutInflater.java:1267)
        at android.view.LayoutInflater.rInflate(LayoutInflater.java:1123)
        at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:1088)
        at android.view.LayoutInflater.parseInclude(LayoutInflater.java:1267)
        at android.view.LayoutInflater.rInflate(LayoutInflater.java:1123)
        at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:1088)
        at android.view.LayoutInflater.inflate(LayoutInflater.java:686)
        at android.view.LayoutInflater.inflate(LayoutInflater.java:538)
        at android.view.LayoutInflater.inflate(LayoutInflater.java:481)
        at androidx.appcompat.app.AppCompatDelegateImpl.setContentView(AppCompatDelegateImpl.java:696)
        at androidx.appcompat.app.AppCompatActivity.setContentView(AppCompatActivity.java:170)
        at androidx.databinding.DataBindingUtil.setContentView(DataBindingUtil.java:303)
        at androidx.databinding.DataBindingUtil.setContentView(DataBindingUtil.java:284)
        at com.domain.news.utils.delegates.ActivityBindingProperty.createActivityBinding(Databinding.kt:20)
        at com.domain.news.utils.delegates.ActivityBindingProperty.getValue(Databinding.kt:16)
        at com.domain.news.ui.activities.MainActivity.getBinding(Unknown Source:10)
        at com.domain.news.ui.activities.MainActivity.setupBinding(MainActivity.kt:42)
        at com.domain.news.ui.activities.MainActivity.onCreate(MainActivity.kt:34)
        at android.app.Activity.performCreate(Activity.java:7893)
        at android.app.Activity.performCreate(Activity.java:7880)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1307)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3282)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3446)
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83)
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2043)
        at android.os.Handler.dispatchMessage(Handler.java:107)
        at android.os.Looper.loop(Looper.java:224)
        at android.app.ActivityThread.main(ActivityThread.java:7548)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:539)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:950)
     Caused by: java.lang.NoSuchMethodException: com.domain.news.ui.fragments.news.NewsFragment.<init> []
        at java.lang.Class.getConstructor0(Class.java:2332)
        at java.lang.Class.getConstructor(Class.java:1728)
        at androidx.fragment.app.Fragment.instantiate(Fragment.java:548)
            ... 66 more

从最后3行我可以看出原因是因为片段构造函数

【问题讨论】:

  • 你能从 logcat 中发布错误吗?还要在片段中显示您正在使用 Navigation.findNavController( ) 的代码。
  • @Rajasekhar 当然,我编辑了问题并添加了更多细节
  • 检查我更新的答案。
  • 请发布导航图

标签: android kotlin android-fragments android-jetpack android-jetpack-navigation


【解决方案1】:

首先,打开你的

app:navGraph="@navigation/navigation

错误清楚地表明它不能膨胀你的 XMl,(可能在你的 @navigation/navigation XML 文件的第 18 行)

【讨论】:

  • 错误指出错误在XML layout 中而不是在导航文件中。行号18指的是FragmentContainerView,因为Args问题,不能膨胀
【解决方案2】:

您需要在片段的参数包中而不是在构造函数中传递数据。 为此NewsSection需要实现Parcelable

在您的导航 xml 中,您可以执行以下操作:

<fragment
        android:id="@+id/newsFragment"
        android:name="com.example.NewsFragment"
        android:label="ProductListerFragment"
        tools:layout="@layout/fragment_news_secion">
        <argument
            android:name="newsSection"
            app:argType="com.example.NewsSection" />

在您正在导航的片段中:

val newsSection = NewsSection(....)
val bundle = bundleOf("newsSection" to newsSection)
view.findNavController().navigate(R.id.newsAction, bundle)

NewsFragment:

val newsSection = arguments?.getParcelable("newsSection") as? NewsSection

更多详情请见https://developer.android.com/guide/navigation/navigation-pass-data

【讨论】:

  • 好吧,如果没有ViewPager,这可能会起作用,但是如果您在实例化一个新片段时查看CategoryFragmentPagerAdapter.kt,我这里有ViewPager adapter,我必须将一个参数传递给片段,并且使用这种方法,我将无法使用导航传递它,因为适配器负责实例化片段,并且我无法在其中使用导航参数
  • 你需要重做你的片段,这样你就不会在构造函数中传递任何东西。片段需要一个无参数的默认构造函数才能正确恢复,并且您会收到有关它的 lint 警告。通常的方法是在伴生对象中有一个 newInstance 函数 - 你用你的参数调用它,它会创建你的 Fragment 并使用你传入的数据设置参数包。然后你在 @ 期间读取参数987654333@,并将片段设置为显示任何内容。就像这里的DetailsFragmentdeveloper.android.com/guide/components/fragments#Example
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多