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

Passing data back to previous fragment from current fragment

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

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

所以,似乎在 B 中我从两个不同的片段中获取数据。我尝试了所有使用 activity 的方法,它与 startActivityforresult 配合使用效果很好。都是碎片我怎么管理

更新

Androidx Activity 1.2.0-alpha02 and Androidx Fragment 1.3.0-alpha4, the official Android developer guide 开始建议使用 Activity/Fragment 结果 APIs 而不是已弃用的 Activity.onActivityResult(int, int, Intent)Fragment.setTargetFragment(Fragment, int) 方法:

it is strongly recommended to use the Activity Result APIs introduced in AndroidX Activity 1.2.0-alpha02 and Fragment 1.3.0-alpha02.

因此,要将数据从 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 中,使用相同的 requestKeysetFragmentResult() API 在相同的 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");   
    }
}

当您将数据从片段 A 发送到片段 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();

并且当您将数据从片段 C 发送到片段 B 时,使用与片段 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 FragemntC

片段B

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

自 2017 年以来情况发生了很大变化。我 post 的答案基本上是 https://developer.android.com 中的一个示例,它提供了一个很好的解决方案,您的片段,无论数量如何,都对每个片段一无所知其他,你仍然能够创建一个简单而优雅的机制,可以毫不费力地使用。

答案基于ViewModels and LiveData

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

以下所有内容均引用自 link: source (Kotlin/Java)

在片段之间共享数据

It's very common that two or more fragments in an activity need to communicate with each other. Imagine a common case of master-detail fragments, where you have a fragment in which the user selects an item from a list and another fragment that displays the contents of the selected item. This case is never trivial as both fragments need to define some interface description, and the owner activity must bind the two together. In addition, both fragments must handle the scenario where the other fragment is not yet created or visible.

This common pain point can be addressed by using ViewModel objects. These fragments can share a ViewModel using their activity scope to handle this communication, as illustrated by the following sample code:

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
        })
    }
}

Notice that both fragments retrieve the activity that contains them. That way, when the fragments each get the ViewModelProvider, they receive the same SharedViewModel instance, which is scoped to this activity.

This approach offers the following benefits:

  • The activity does not need to do anything, or know anything about this communication.
  • Fragments don't need to know about each other besides the SharedViewModel contract. If one of the fragments disappears, the other one keeps working as usual.
  • Each fragment has its own lifecycle, and is not affected by the lifecycle of the other one. If one fragment replaces the other one, the UI continues to work without any problems.