我在起始目标位置添加了一个可为空的参数:
<?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>
但是当我加载应用程序时,出现以下异常:
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)
该异常是由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
...
}
这是MyDataObject的代码:
@Parcelize
data class MyDataObject (
val id: String,
val name: String,
val externalIdentifier: String
val type: MyDataEnumType,
var responsibleUser: SomeOtherParcelableClass?
): Parcelable
我不明白的是导航控制器没有正确地传递我的起始目的地参数。我在这里想念东西吗?
答案 0 :(得分:4)
你好,我想你想实现以下目标
BeforeFragment --arg--> StartFragment --> AfterFragment
此流程类似于初次使用的用户,也就是返回的用户流程。这里BeforeFragment
是login_nav_graph
嵌套图中的最后一个片段。 StartFragment
是main_nav_graph
的起始目的地。 StartFragment
是用户返回的第一个屏幕。
因此,您可以在BeforeFragment
中将args设置如下
val userJohn:User = User(34, "John", 645, UserType.TYPE2, Guardian("Mike"))
val action = BeforeFragmentDirections.actionGlobalStart(userJohn)
findNavController().navigate(action)
在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
可以找到样本回购here
我的最佳猜测
此问题是由于旧版导航中的错误所致,请使用示例存储库中使用的2.2.0-alpha01
。
为了解决移至新导航版本时发生的错误 在您的模块gradle文件中添加以下内容
android {
...
kotlinOptions {
jvmTarget = "1.8" // set your Java version here
}
}
这可以纠正错误
无法内联字节码...
不建议您记住将复杂对象作为参数传递。引自docs。
通常,您应该强烈建议只传递最小的金额 目的地之间的数据量。例如,您应该将密钥传递给 检索对象而不是传递对象本身,作为总数 在Android上,所有已保存状态的空间都受到限制。如果您需要通过 大量数据,请考虑使用ViewModel中所述 在片段之间共享数据。
如果这可以解决您的问题,请确认答案,因为我花了大量时间准备这篇文章。
答案 1 :(得分:0)
如果您创建一个带有捆绑软件的片段,但没有NavController.navigate,并且您仍然希望将“ by navArgs()”保留在目标片段中,例如,因为要在测试时在launchFragmentInContainer中使用它,请使用try / catch 。在开始检查可为空的类型之前,将引发IllegalStateException。
private fun updateArguments(){
this.title = try{
val args: DestinationFragmentArgs by navArgs()
if (args.dataObject?.name == ""){
// default value provided so check whether bundle was used
arguments?.getString("name") ?: ""
}else {
args?.venueId
}
}catch (ex: Exception){
// fragment created without using NavController.navigate
arguments?.getString("venueId") ?: ""
}
}
房间非常快,因此从id检索对象作为参数不成问题,因此,如果可能,请尝试对参数使用基本类型,否则对廉价对象使用Parcelable或Serialize。