将数据从当前片段传回前一个片段

Posted

技术标签:

【中文标题】将数据从当前片段传回前一个片段【英文标题】:Passing data back to previous fragment from current fragment 【发布时间】:2017-07-31 09:28:53 【问题描述】:

我在我的应用程序中使用导航抽屉。我有一个 MainActivity,其余的是 Fragments。所以问题是假设我有三个片段,如 A、B、C。

现在在 A 中,我有一个按钮,我正在从 A>B 发送数据。 例如 putSring("来自 A 的数据","来自 A 的数据"); 现在在 B 我从 A 接收数据。 我在 B 中有一个按钮,我正在从 B>C 发送数据。 例如 putSring("来自 B 的数据","来自 B 的数据"); 现在在 C 中,我从 B 接收数据。 然后,我在 C 中有一个 Button,并从 C>B 发送数据。 例如 putSring("来自 C 的数据","来自 C 的数据");

所以,似乎在 B 中,我从两个不同的片段中获取数据。我尝试了所有使用活动,它与 startActivityforresult 配合得很好。但是当一切都是碎片时,我该如何管理。

【问题讨论】:

当你从 A->B 发送数据时,你必须维护我来自 A 的 BOOLEAN 和相同的情况 C->A ,你必须使用相同的 BOOLEAN 来指定你来自c并向B发送数据 但我将如何检查?它是从哪个片段传递过来的 当你从 A->B 发送数据时,使用 BOOLEAN 值 TRUE .....当你从 C->A 发送数据时,使用 BOOLEAN 值 FALSE 但是当你从 A>B 传递数据时,应用程序会因 NPE 而崩溃。理由是它不会误认为 C>B ..明白了吗? 如果一次只有一个片段处于活动状态,似乎在 B 中我从两个不同的片段中获取数据 是不可能的。此外,如果您在 Fragment 对象上使用 setArguments(),则不必担心。 【参考方案1】:

更新

androidx Activity 1.2.0-alpha02 和Androidx Fragment 1.3.0-alpha4 开始,the official Android developer guide 建议在已弃用的Activity.onActivityResult(int, int, Intent)Fragment.setTargetFragment(Fragment, int) 方法上使用Activity/Fragment Result API:

强烈建议使用 AndroidX Activity 1.2.0-alpha02 和 Fragment 1.3.0-alpha02 中引入的 Activity Result API。

因此,要将数据从 C 传回片段 B,请在片段 B 的 FragmentManager 上调用 setFragmentResultListener(),如下例所示:

override fun onCreate(savedInstanceState: Bundle?) 
    super.onCreate(savedInstanceState)
    // Use the Kotlin extension in the fragment-ktx artifact
    setFragmentResultListener("requestKey")  requestKey, bundle ->
        // We use a String here, but any type that can be put in a Bundle is supported
        val result = bundle.getString("bundleKey")
        // Do something with the result
     

在片段 C 中,使用 setFragmentResult() API 使用相同的 requestKey 将结果设置在相同的 FragmentManager 上。示例:

setFragmentResult("requestKey", bundleOf("bundleKey" to "result"))

更多详情请访问this guide。


不推荐使用以下答案

您可以在从 B 启动 Fragment C 时调用 setTargetFragment()。示例:

FragmentC fragmentC = FragmentC.newInstance();
fragmentC.setTargetFragment(FragmentB.this, REQUEST_CODE);
getFragmentManager().beginTransaction().replace(R.id.container, fragmentC).commit();

然后当你想将数据从C传回片段B时,可以调用如下代码:

getTargetFragment().onActivityResult(
                getTargetRequestCode(),
                Activity.RESULT_OK,
                new Intent().putExtra("datafrom C", "datafrom C")
);

并从片段 B 中的 onActivityResult() 方法获取它:

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) 
    if (requestCode==REQUEST_CODE && resultCode==Activity.RESULT_OK) 
        String datafromC = data.getStringExtra("datafrom C");   
    

【讨论】:

无法解析 newInstance() 也无法解析 REQUEST_CODE newInstance() 是我一直用来初始化片段的方法,你可以调用 FragmentC fragmentC = new FragmentC();而是。 REQUEST_CODE 是一个常量整数,它可以让您识别哪个片段被触发 onActivityResult() 方法,如果片段 C 是唯一传递数据的片段,您可以为其分配一个整数回到你的片段 BEG fragmentC.setTargetFragment(FragmentB.this, 1);然后在fragment B的onActivityResult()方法中检查requestCode==1。 这样一种简洁、简单、原生的方式。然而,似乎很多人对此一无所知 @KirillStarostin 手动调用ActivityResult 到底有什么好处?【参考方案2】:

当你将数据从 Fragment A 发送到 Fragment B 时,使用相同的布尔值,如下所示:-

片段A -> 片段B

FragmentB ldf = new FragmentB ();
Bundle args = new Bundle();
args.putBoolean("BOOLEAN_VALUE",true);
ldf.setArguments(args);

getFragmentManager().beginTransaction().add(R.id.container, ldf).commit();

当你从 Fragment C 向 Fragment B 发送数据时,使用与 Fragment A 到 B 相同的 BOOLEAN,如下所示-

片段C -> 片段B

FragmentB ldf = new FragmentB ();
    Bundle args = new Bundle();
    args.putBoolean("BOOLEAN_VALUE",false);
    ldf.setArguments(args);

    getFragmentManager().beginTransaction().add(R.id.container, ldf).commit();

最后我们必须检查 FragmentB 中收到的值是否来自 Fragment A OR FragmentC

片段B

   Boolean getValue= getArguments().getBoolean("BOOLEAN_VALUE");  
   if(getValue)
   
    //VALUE RECEIVED FROM FRAGMENT A
   
   else
   
   //VALUE RECEIVED FROM FRAGMENT C
   

【讨论】:

不错的一个..我正在尝试但将其设为布尔值 @chris ,对不起,我已经更新了解决方案..请检查一下..让我知道它是否适合你 @chris ..它对你有用吗?比请标记正确的答案,因为这将有助于其他人在未来也陷入困境 但是当我来自 C>B 时,我从 A 获得的值将变为 null A 的值有什么用,而你来自 C->B....你可以做的还有一件事是......你发送 A 的值来自B->C..而且你可以从 C->B 收回它【参考方案3】:

自 2017 年以来情况发生了很大变化。我发布的答案基本上是来自 https://developer.android.com 的一个示例,它提供了一个很好的解决方案,您的片段(无论数量如何)彼此不了解,但您仍然可以创建一种简单而优雅的机制,可以毫不费力地使用。

答案基于ViewModels和LiveData。

注意:如果您不熟悉Architecture Components,我强烈建议您随时尽可能多地了解它,因为它会提高您的生产速度并减少项目中的错误数量.

以下所有内容均来自以下链接: source (Kotlin/Java)

在片段之间共享数据

一个活动中的两个或多个片段需要 相互交流。想象一个常见的主从案例 片段,您有一个片段,用户在其中选择一个项目 从一个列表和另一个显示 选定的项目。这种情况绝非易事,因为两个片段都需要 定义一些接口描述,并且必须绑定所有者活动 两者在一起。此外,两个片段都必须处理场景 另一个片段尚未创建或可见。

这个常见的痛点可以通过使用 ViewModel 对象来解决。 这些片段可以使用它们的活动范围共享一个 ViewModel 处理此通信,如以下示例所示 代码:

class SharedViewModel : ViewModel() 
    val selected = MutableLiveData<Item>()

    fun select(item: Item) 
        selected.value = item
    


class MasterFragment : Fragment() 

    private lateinit var itemSelector: Selector

    // Use the 'by activityViewModels()' Kotlin property delegate
    // from the fragment-ktx artifact
    private val model: SharedViewModel by activityViewModels()

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) 
        super.onViewCreated(view, savedInstanceState)
        itemSelector.setOnClickListener  item ->
            // Update the UI
        
    


class DetailFragment : Fragment() 

    // Use the 'by activityViewModels()' Kotlin property delegate
    // from the fragment-ktx artifact
    private val model: SharedViewModel by activityViewModels()

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) 
        super.onViewCreated(view, savedInstanceState)
        model.selected.observe(viewLifecycleOwner, Observer<Item>  item ->
            // Update the UI
        )
    

请注意,两个片段都会检索包含它们的活动。 这样,当片段各自获得 ViewModelProvider 时,它们 接收相同的 SharedViewModel 实例,该实例的范围仅限于此 活动。

这种方法有以下好处:

活动不需要做任何事情,或者对此一无所知 沟通。 片段不需要相互了解,除了 SharedViewModel 合同。如果其中一个碎片消失, 另一个继续照常工作。 每个片段都有自己的生命周期, 并且不受另一个生命周期的影响。如果一个片段 替换另一个,用户界面继续工作,没有任何问题。

【讨论】:

以上是关于将数据从当前片段传回前一个片段的主要内容,如果未能解决你的问题,请参考以下文章

Relay.js 没有正确解析组合片段

从另一个片段打开一个片段始终保留前一个片段标题

如何将数据从一个片段传输到另一个片段android

刷新同一活动中剩余的当前片段(ListView 数据)

如何使用java将数据从片段传递到android中的另一个片段?

将数据从一个片段发送到另一个片段时出错。 (两个片段都由一个活动托管)