【发布时间】:2021-07-10 00:48:17
【问题描述】:
我使用navigation component 进行各种屏幕转换。
在屏幕切换的同时将title data从A fragment传递给B fragment。 (使用safe args)
在片段B中,设置从A接收的数据。
并且为了保持title data即使在屏幕切换时,我将它设置在LiveData中的ViewModel中。
但是如果你从fragment B回到fragment C,
B 的标题不见了。
有人说因为这是replace()的方法,所以每次切换屏幕都会创建一个新的fragment。
在导航组件中切换屏幕时如何保留数据?
注意:所有屏幕转换都使用 findNavController.navigate()!
片段 A
startBtn?.setOnClickListener { v ->
title = BodyPartCustomView.getTitle()
action = BodyPartDialogFragmentDirections.actionBodyPartDialogToWrite(title)
findNavController()?.navigate(action)
}
片段 B
class WriteRoutineFragment : Fragment() {
private var _binding: FragmentWritingRoutineBinding? = null
private val binding get() = _binding!!
private val viewModel: WriteRoutineViewModel by viewModels { WriteRoutineViewModelFactory() }
private val args : WriteRoutineFragmentArgs by navArgs() // When the screen changes, it is changed to the default value set in <argument> of nav_graph
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewModel.setValue(args) // set Data to LiveData
viewModel.title.observe(viewLifecycleOwner) { titleData ->
// UI UPDATE
binding.title.text = titleData
}
}
更新的导航图.xml
<?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/calendar">
<!-- fragment A -->
<dialog
android:id="@+id/bodyPartDialog"
android:name="com.example.writeweight.fragment.BodyPartDialogFragment"
android:label="BodyPartDialogFragment"
tools:layout="@layout/fragment_body_part_dialog">
<action
android:id="@+id/action_bodyPartDialog_to_write"
app:destination="@id/write"/>
</dialog>
<!-- fragment B -->
<fragment
android:id="@+id/write"
android:name="com.example.writeweight.fragment.WriteRoutineFragment"
android:label="WritingRoutineFragment"
tools:layout="@layout/fragment_writing_routine">
<action
android:id="@+id/action_write_to_workoutListTabFragment"
app:destination="@id/workoutListTabFragment" />
<argument
android:name="title"
app:argType="string"
android:defaultValue="Unknown Title" />
</fragment>
<!-- fragment C -->
<fragment
android:id="@+id/workoutListTabFragment"
android:name="com.example.writeweight.fragment.WorkoutListTabFragment"
android:label="fragment_workout_list_tab"
tools:layout="@layout/fragment_workout_list_tab" >
<action
android:id="@+id/action_workoutListTabFragment_to_write"
app:destination="@id/write"
app:popUpTo="@id/write"
app:popUpToInclusive="true"/>
</fragment>
</navigation>
更新的 ViewModel( 这是 B 片段的视图模型。)
class WriteRoutineViewModel : ViewModel() {
private var _title: MutableLiveData<String> = MutableLiveData()
val title: LiveData<String> = _title
fun setValue(_data: WritingRoutineFragmentArgs) {
_title.value = _data.title
}
}
错误
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.writeweight, PID: 25505
java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:612)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1130)
Caused by: java.lang.reflect.InvocationTargetException
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:602)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1130)
Caused by: java.lang.reflect.InvocationTargetException
at java.lang.reflect.Method.invoke(Native Method)
at androidx.navigation.NavArgsLazy.getValue(NavArgsLazy.kt:52)
at androidx.navigation.NavArgsLazy.getValue(NavArgsLazy.kt:34)
at com.example.writeweight.fragment.WriteRoutineFragment.getArgs(Unknown Source:4)
at com.example.writeweight.fragment.WriteRoutineFragment.onViewCreated(WriteRoutineFragment.kt:58)
at androidx.fragment.app.Fragment.performViewCreated(Fragment.java:2987)
at androidx.fragment.app.FragmentStateManager.createView(FragmentStateManager.java:546)
at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:282)
at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:2189)
at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:2106)
at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:2002)
at androidx.fragment.app.FragmentManager$5.run(FragmentManager.java:524)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:246)
at android.app.ActivityThread.main(ActivityThread.java:8512)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:602)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1130)
Caused by: java.lang.IllegalArgumentException: Required argument "title" is missing and does not have an android:defaultValue
at com.example.writeweight.fragment.WriteRoutineFragmentArgs$Companion.fromBundle(WriteRoutineFragmentArgs.kt:26)
at com.example.writeweight.fragment.WriteRoutineFragmentArgs.fromBundle(Unknown Source:2)
【问题讨论】:
-
在我看来问题出在
viewModel.setValue(args)。如果标题的 args 值丢失,这个函数会做什么?当您导航回 B 时可能会出现这种情况? -
它似乎设置为我为
nav_graph设置的默认值,正如我所料。事实上,它被设置为默认值。更新nav_graph。但是如何在没有viewModel.setValue的情况下在LiveData中设置值? -
我会让 title 参数为 null 并传递 null 作为默认值。然后在
viewModel.setValue()中,如果它为 null 则忽略它,而不是将其传递给 LiveData。 -
我需要知道错误是什么并查看您的
setValue()代码以了解发生了什么问题。
标签: android kotlin android-fragments android-navigation