Jetpack 导航组件在加载具有可为空参数的起始目标时抛出 IllegalStateException

Seb*_*ien 6 android kotlin android-jetpack android-jetpack-navigation

我向开始目的地添加了一个可为空的参数:

<?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"
        android:id="@+id/nav_graph"
        app:startDestination="@id/startDest">

    <fragment android:id="@+id/startDest"
          android:name="com.myapp.MyStartFragment"
          android:label="Start"
          tools:layout="@layout/fragment_start">
        <argument
            android:name="dataObject"
            app:argType="com.myapp.MyDataObject"
            android:defaultValue="@null"
            app:nullable="true"/>
        ...
    </fragment>
    ...
</navigation>
Run Code Online (Sandbox Code Playgroud)

但是当我加载我的应用程序时,我收到以下异常:

java.lang.IllegalStateException: Fragment MyStartFragment{a4ffd1f (ca52d4dc-ff36-4a93-8ebf-f11af7b7d5aa) id=0x7f080145} has null arguments
    at com.myapp.MyStartFragment$$special$$inlined$navArgs$1.invoke(FragmentNavArgsLazy.kt:42)
    at com.myapp.MyStartFragment$$special$$inlined$navArgs$1.invoke(Unknown Source:0)
    at androidx.navigation.NavArgsLazy.getValue(NavArgsLazy.kt:44)
    at androidx.navigation.NavArgsLazy.getValue(NavArgsLazy.kt:34)
    at com.myapp.MyStartFragment.getArgs(Unknown Source:27)
    at com.myapp.MyStartFragment.onAttach(MyStartFragment.kt:85)
Run Code Online (Sandbox Code Playgroud)

而异常是由 MyStartFragment 中的这段代码触发的:

private val args: MyStartFragmentArgs by navArgs()
override fun onAttach(context: Context) {
    super.onAttach(context)
    val title = if(this.args.dataObject == null) getString(R.string.start_list_title) else this.args.dataObject!!.name
    ...
}
Run Code Online (Sandbox Code Playgroud)

这是 MyDataObject 的代码:

@Parcelize
data class MyDataObject (
    val id: String,
    val name: String,
    val externalIdentifier: String
    val type: MyDataEnumType,
    var responsibleUser: SomeOtherParcelableClass?
): Parcelable 
Run Code Online (Sandbox Code Playgroud)

我不明白的是,我的起始目的地没有通过导航控制器正确传递参数。我在这里错过了什么吗?

use*_*158 7

您好,我假设您想实现以下目标

BeforeFragment --arg--> StartFragment --> AfterFragment
Run Code Online (Sandbox Code Playgroud)

示例导航图

此流程类似于首次用户,返回用户流程。这BeforeFragmentlogin_nav_graph嵌套图中的最后一个片段。StartFragment是 的起始目的地main_nav_graphStartFragment是返回用户看到的第一个屏幕。

所以在BeforeFragment你可以设置 args 如下

val userJohn:User = User(34, "John", 645, UserType.TYPE2, Guardian("Mike"))
val action = BeforeFragmentDirections.actionGlobalStart(userJohn)
findNavController().navigate(action)
Run Code Online (Sandbox Code Playgroud)

并且StartFragment你可以像你已经做过的那样做

title = if(this.args.user == null)
   getString(R.string.user_name) // mocks loading saved user name
else
   this.args.user?.name // when user is first time user read from passed args
Run Code Online (Sandbox Code Playgroud)

可以在此处找到示例回购


我最好的猜测

此问题是由于旧导航版本中的错误造成的,因此请使用2.2.0-alpha01我在示例存储库中使用的那个。

为了修复在模块 gradle 文件中移动到新导航版本时发生的错误,请添加以下内容

android {
    ...
    kotlinOptions {
        jvmTarget = "1.8" // set your Java version here
    }
}
Run Code Online (Sandbox Code Playgroud)

这修复了错误

无法内联字节码...


请记住,不建议将复杂对象作为参数传递。引用自docs

通常,您应该强烈希望在目的地之间只传递最少量的数据。例如,您应该传递一个键来检索一个对象,而不是传递对象本身,因为所有保存状态的总空间在 Android 上是有限的。如果您需要传递大量数据,请考虑使用在片段之间共享数据中所述的 ViewModel。

如果这解决了您的问题,请确认答案,因为我花了很多时间准备这篇文章。