将数据从当前片段传回前一个片段
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 合同。如果其中一个碎片消失, 另一个继续照常工作。 每个片段都有自己的生命周期, 并且不受另一个生命周期的影响。如果一个片段 替换另一个,用户界面继续工作,没有任何问题。
【讨论】:
以上是关于将数据从当前片段传回前一个片段的主要内容,如果未能解决你的问题,请参考以下文章