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

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

问题描述

我正在尝试使用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?

您要开始创建一个片段,然后从该片段中接收结果,这似乎是startActivityForResult Activity方法.

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天全站免登陆