如何在使用导航组件导航时保存片段状态 [英] How to save fragment state while navigating with navigation component

查看:40
本文介绍了如何在使用导航组件导航时保存片段状态的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用 android 架构组件创建单个活动应用程序.我有一个片段 A,它有一些文本字段,当用户按下按钮时,我导航到片段 B,在该应用使用如下代码导航回 A 后,他上传并编辑一些图像:

I'm trying to create a single activity app using android architecture components. I have a fragment A which has some textfields, when user pushes a button I navigate to fragment B where he uploads and edits some images after that app navigates back to A using code like this:

findNavController().navigate(R.id.action_from_B_to_A, dataBundle)

当导航回 B 时,使用 dataBundle 将一些数据传递给 A.问题在于所有文本字段都重置了,因为片段 A 基本上是从头开始重新创建的.我在某处读到谷歌的开发人员建议您可以将视图保存在 var 中,而不是每次都对其进行膨胀.所以尝试这样做:

When navigating back B passes some data to A using dataBundle. The problem with this is all the textfields reset because Fragment A is basically recreated from scratch. I read somewhere that a developer from google suggests that you can just save view in a var instead of inflating it everytime. So tried doing that:

private var savedViewInstance: View? = null

override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
): View? {
    return if (savedViewInstance != null) {
        savedViewInstance
    } else {
        savedViewInstance =
                inflater.inflate(R.layout.fragment_professional_details, container, false)
        savedViewInstance
    }
}

但这不起作用,导航回 A 时所有文本字段都会重置.我做错了什么?处理此类案件的正确方法是什么?

But this does not work, all the textfields reset when navigating back to A. What am I doing wrong? What is proper way of handling cases like this?

推荐答案

我会一一回答你的问题.

I will answer your questions one by one.

但这不起作用,所有文本字段在导航回来时都会重置A. 我做错了什么?

But this does not work, all the textfields reset when navigating back to A. What am I doing wrong?

在 FragmentB 中,当用户完成工作并且应用调用以下方法返回 FragmentA.

From FragmentB, when users finish their work and the app call the below method to return FragmentA.

findNavController().navigate(R.id.action_from_B_to_A, dataBundle)

您预计该应用程序会将用户带回 FragmentA,但实际结果是创建了一个新的 FragmentA 并将其放在返回堆栈的顶部.现在返回堆栈将是这样的.

You expected that the app will bring users back to FragmentA, but the actual result is a new FragmentA is created and put on the top of the back stack. Now the back stack will be like this.

FragmentA (new instance)
FragmentB
FragmentA (old instance)

这就是为什么您看到所有文本字段都重置的原因,因为它是 FragmentA 的全新实例.

That why you see all textfields reset, because it is a totally new instance of FragmentA.

处理此类案件的正确方法是什么?

What is proper way of handling cases like this?

你想启动一个片段,然后从那个片段接收结果,它看起来像Activity的startActivityForResult方法.

You want to start a fragment, then receive result form that fragment, it seems like startActivityForResult method of Activity.

Android Dev Summit 2019 - 架构组件中,2:43,有个问题请教 Android 开发者.

In Android Dev Summit 2019 - Architecture Components, at 2:43, there is a question for Android developers.

我们可以为导航添加类似 startFragmentForResult 的东西吗?控制器?

Can we have something like startFragmentForResult for the Navigation Controller?

答案是他们正在研究它,并且将来会提供此功能.

The answer is they are working on it, and this feature will be available in future.

回到你的问题,这是我的解决方案.

Back to your problem, here is my solution.

步骤 1: 创建一个名为 SharedViewModel

class SharedViewModel : ViewModel() {

    // This is the data bundle from fragment B to A
    val bundleFromFragmentBToFragmentA = MutableLiveData<Bundle>()
}

第 2 步:将这些代码行添加到 FragmentA

Step 2: Add these lines of code to FragmentA

private lateinit var viewModel: SharedViewModel

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)

    viewModel = ViewModelProviders.of(requireActivity()).get(SharedViewModel::class.java)
    viewModel.bundleFromFragmentBToFragmentA.observe(viewLifecycleOwner, Observer {
        // This will execute when fragment B set data for `bundleFromFragmentBToFragmentA`
        // TODO: Write your logic here to handle data sent from FragmentB
        val message = it.getString("ARGUMENT_MESSAGE", "")
        Toast.makeText(requireActivity(), message, Toast.LENGTH_SHORT).show()
    })
}

第 3 步:将这些代码行添加到 FragmentB

Step 3: Add these lines of code to FragmentB

// 1. Declare this as class's variable
private lateinit var viewModel: SharedViewModel

// 2. Use the following code when you want to return FragmentA           
// findNavController().navigate(R.id.action_from_B_to_A) // Do not use this one

// Set data for `bundleFromFragmentBToFragmentA`
val data = Bundle().apply { putString("ARGUMENT_MESSAGE", "Hello from FragmentB") }
viewModel.bundleFromFragmentBToFragmentA.value = data

// Pop itself from back stack to return FragmentA
requireActivity().onBackPressed()

这篇关于如何在使用导航组件导航时保存片段状态的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆