我在我的应用程序中使用导航抽屉。我有一个MainActivity,其余的是片段。所以问题是假设我有三个片段,如A、B、C。
现在在A中,我有一个按钮,我正在从A发送数据
所以,在B中,我似乎从两个不同的片段中获取数据。我尝试了所有使用活动的方法,它在startActivityfor结果中运行良好。但是当所有都是片段时,我如何管理?
更新
从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实例,该实例的范围仅限于此活动。
这种方法提供以下好处: