提问者:小点点

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


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

现在在A中,我有一个按钮,我正在从A发送数据

所以,在B中,我似乎从两个不同的片段中获取数据。我尝试了所有使用活动的方法,它在startActivityfor结果中运行良好。但是当所有都是片段时,我如何管理?


共3个答案

匿名用户

更新

从Androidx Activity 1.2.0-alpha02和Androidx Fragment 1.3.0-alpha4开始,官方Android开发人员指南建议在已弃用的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使用相同的request estKey在同一个FragmentManager上设置结果。示例:

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

更多细节可以在本指南中找到。

以下答案已废弃

当您从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");   
    }
}

匿名用户

当u将数据从片段A发送到片段B时,使用如下相同的布尔值:-

片段A-

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

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

当u将数据从片段C发送到片段B时,使用与片段A到B相同的BOOLEAN,如下所示-

片段C-

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或FragemntC

碎片B

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

匿名用户

自2017年以来,事情发生了很大变化。我发布的答案基本上是https://developer.android.com中的一个例子,它提供了一个很好的解决方案,在这个解决方案中,您的片段,无论数量如何,都不了解彼此,但您仍然能够创建一个简单而优雅的机制,无需太多努力即可使用。

答案基于ViewModels和LiveData。

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

下面的所有内容都是来自以下链接的引用:来源(静态编程语言/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合约之外,片段不需要相互了解。如果其中一个片段消失,另一个片段会照常工作。
  • 每个片段都有自己的生命周期,不受另一个片段生命周期的影响。如果一个片段替换另一个片段,UI继续工作,没有任何问题。