将数据从嵌套片段发送到父片段
Posted
技术标签:
【中文标题】将数据从嵌套片段发送到父片段【英文标题】:Sending data from nested fragments to parent fragment 【发布时间】:2014-06-02 07:18:03 【问题描述】:我有一个Fragment
FR1
,其中包含几个Nested
Fragments
; FRa
、FRb
、FRc
。这些Nested
Fragments
通过在FR1
的布局上按Buttons
进行更改。每个Nested
Fragments
中都有几个输入字段;其中包括 EditTexts
、NumberPickers
和 Spinners
之类的内容。当我的用户完成并填写Nested
Fragments
的所有值时,FR1
(父片段)有一个提交按钮。
然后我怎样才能从我的Nested
Fragments
中检索我的值并将它们带入FR1
。
-
在每个
Nested
Fragment
中声明并以编程方式处理所有 Views
。
父Fragment
、FR1
处理Nested
Fragments
的事务。
我希望这个问题足够清楚,我不确定是否需要发布代码,但如果有人觉得我可以这样做。
编辑 1:
这是我添加Nested
Fragments
的方法:
tempRangeButton.setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View v)
getChildFragmentManager().beginTransaction()
.add(R.id.settings_fragment_tertiary_nest, tempFrag)
.commit();
);
scheduleButton.setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View v)
getChildFragmentManager().beginTransaction()
.add(R.id.settings_fragment_tertiary_nest, scheduleFrag)
.commit();
);
alertsButton.setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View v)
getChildFragmentManager().beginTransaction()
.add(R.id.settings_fragment_tertiary_nest, alertsFrag)
.commit();
);
submitProfile.setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View v)
constructNewProfile();
);
我的constructNewProfile()
方法需要来自我的Nested
Fragments
的值。
public Fragment tempFrag = fragment_profile_settings_temperature
.newInstance();
public Fragment scheduleFrag= fragment_profile_settings_schedules
.newInstance();
public Fragment alertsFrag = fragment_profile_settings_alerts
.newInstance();
以上是指父Fragment的字段;以及它们最初是如何实例化的。
【问题讨论】:
也看看我的问题***.com/questions/70721218/…和***.com/questions/70680327/… 【参考方案1】:片段之间的数据传递可以通过 FragmentManager 完成。从 Fragment 1.3.0-alpha04 开始,我们可以使用 setFragmentResultListener() 和 setFragmentResult() API 在 Fragment 之间共享数据。
Official Documentation
【讨论】:
【参考方案2】:回答太晚了,我可以建议在子片段中创建 EditText 对象
EditText tx;
在 Oncreateview 中初始化它。然后为桥创建另一个类,例如
public class bridge
public static EditText text = null;
现在在父片段中获得它的引用。
EditText childedtx = bridge.text;
现在点击方法获取值
onclick(view v)
childedtx.getText().tostring();
在我的项目中进行了测试,它的工作就像魅力一样。
【讨论】:
【参考方案3】:您可以在片段之间使用共享数据。
public class SharedViewModel extends ViewModel
private final MutableLiveData<Item> selected = new MutableLiveData<Item>();
public void select(Item item)
selected.setValue(item);
public LiveData<Item> getSelected()
return selected;
public class MasterFragment extends Fragment
private SharedViewModel model;
public void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
itemSelector.setOnClickListener(item ->
model.select(item);
);
public class DetailFragment extends Fragment
public void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
SharedViewModel model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
model.getSelected().observe(this, item ->
// Update the UI.
);
更多信息ViewModel Architecture
【讨论】:
【参考方案4】:不使用接口,你可以通过下面的方式调用子fragment:
( (YourFragmentName) getParentFragment() ).yourMethodName();
【讨论】:
这应该是接受的答案恕我直言。它是一行代码,完全符合需要。希望我能多点赞 如果可能,您应该避免使用此解决方案。片段的全部意义在于它是 UI 的可重用部分。如果您的子片段包含对父片段的硬编码引用,那么您将失去对子片段的可重用性。这就是接口很棒的原因,父母会选择如何实现它们。 除了懒惰和不正确使用片段之外,这不是一个好的解决方案。如果子 Fragment 知道父 Fragment 是什么类,那么您可能不应该创建子 Fragment,而只需将代码放在父 Fragment 中即可。 @uDevel 有时您必须使用子 Fragment - 假设您希望在父 Fragment 中有标签。在这种情况下,子 Fragment 可能只与父 Fragment 一起工作。我想在这种情况下,单线解决方案很棒。 这不是一个好的解决方案。您的子片段与您的父片段紧密耦合【参考方案5】:在片段之间传递数据的最佳方式是使用接口。这是您需要做的: 在你嵌套的片段中:
public interface OnDataPass
public void OnDataPass(int i);
OnDataPass dataPasser;
@Override
public void onAttach(Activity a)
super.onAttach(a);
dataPasser = (OnDataPass) a;
public void passData(int i)
dataPasser.OnDataPass(i);
在你的父片段中:
public class Fragment_Parent extends Fragment implements OnDataPass
...
@Override
public void OnDataPass(int i)
this.input = i;
btnOk.setOnClickListener(new OnClickListener()
@Override
public void onClick(View v)
Fragment fragment = getSupportFragmentManager().findFragmentByTag("0");
((Fragment_Fr1) fragment).passData();
【讨论】:
onAttach(Activity a)
现已弃用。相反,我实现了onAttach(@NonNull Context context)
,但dataPasser = (OnDataPass) context;
给了我一个致命的异常:java.lang.ClassCastException: com.myapp.MainActivity 不能转换为 com.myapp.OnDataPass。
当我定义时它起作用了:dataPasser = (OnDataPass) getParentFragment();
。不好吗?【参考方案6】:
最好的方法是使用接口:
在嵌套片段中声明一个接口
// Container Activity or Fragment must implement this interface
public interface OnPlayerSelectionSetListener
public void onPlayerSelectionSet(List<Player> players_ist);
将接口附加到父片段
// In the child fragment.
public void onAttachToParentFragment(Fragment fragment)
try
mOnPlayerSelectionSetListener = (OnPlayerSelectionSetListener)fragment;
catch (ClassCastException e)
throw new ClassCastException(
fragment.toString() + " must implement OnPlayerSelectionSetListener");
@Override
public void onCreate(Bundle savedInstanceState)
Log.i(TAG, "onCreate");
super.onCreate(savedInstanceState);
onAttachToParentFragment(getParentFragment());
// ...
在按钮点击时调用监听器。
// In the child fragment.
@Override
public void onClick(View v)
switch (v.getId())
case R.id.tv_submit:
if (mOnPlayerSelectionSetListener != null)
mOnPlayerSelectionSetListener.onPlayerSelectionSet(selectedPlayers);
break;
让你的父片段实现接口。
public class Fragment_Parent extends Fragment implements Nested_Fragment.OnPlayerSelectionSetListener
// ...
@Override
public void onPlayerSelectionSet(final List<Player> players_list)
FragmentManager fragmentManager = getChildFragmentManager();
SomeOtherNestFrag someOtherNestFrag = (SomeOtherNestFrag)fragmentManager.findFragmentByTag("Some fragment tag");
//Tag of your fragment which you should use when you add
if(someOtherNestFrag != null)
// your some other frag need to provide some data back based on views.
SomeData somedata = someOtherNestFrag.getSomeData();
// it can be a string, or int, or some custom java object.
在进行片段交易时添加标签,以便您可以在之后查找它以调用其方法。 FragmentTransaction
这是处理片段和嵌套片段之间通信的正确方法,对于活动和片段几乎相同。 http://developer.android.com/guide/components/fragments.html#EventCallbacks
其实官方还有另外一种方式,就是使用activity result,不过这个已经够用了,也很常用。
【讨论】:
getParentFragment() 仅适用于 API 17+,因此此答案应明确说明,否则不够清楚 @uDevelonAttachFragment(getParentFragment());
(在第 2 步中)有什么作用?是在Activity
吗?
@ShrimpCrackers 可能会有些混淆,因为由于原生 Android 中的 Support Library v24.0.0
或 API 24,Google 工程师引入了一种名为 onAttachFragment(Fragment) 的新方法,它实际上与此答案中的方法略有不同这里。 uDevei 2年前写这个答案时恰好选择了相同的方法名称。需要明确的是:您没有覆盖 Android 框架中的 onAttachFragment()
,您是在实现您自己的。
@TonyChan 感谢您澄清困惑。由于谷歌创建了一个同名的新方法,我想用一个更好的方法名称来更新这个答案,但我想不出一个不那么容易混淆的名字。来自谷歌的那个实际上命名不正确,imo。通过阅读它的作用,它应该被称为 onChildFragmentAttached。
将方法名称更新为 onAttachToParentFragment 以避免与 Google 的方法混淆。【参考方案7】:
在获取更好的父片段之前检查instanceOf
:
if (getParentFragment() instanceof ParentFragmentName)
getParentFragment().Your_parent_fragment_method();
【讨论】:
【参考方案8】:您可以使用getChildFragmentManager()
并找到嵌套片段,获取它们并运行一些方法来检索输入值
【讨论】:
我已经使用 childFragmentManager 最初在我的父片段中提交交易;但是,当我尝试在某些父片段的方法中调用 getChildFragmentManager() 时,它会返回错误。 所以 FR1 有方法 "constructFRaProfile()";我在 FR1 中点击提交后调用它。我应该调用 childFragmentManager().findFragmentByTag("FRa"); 吗?然后开始检索值? 我不确定我是否正确设置了标签; android是自动为子fragment设置标签还是必须手动设置? 您是如何使用您的子片段的?从代码添加或在 XML 布局中使用它们 @Jedil 你不能在 XML 中添加子片段,它们必须以编程方式添加以上是关于将数据从嵌套片段发送到父片段的主要内容,如果未能解决你的问题,请参考以下文章
如何将数据从 BottomSheetDialogFragment 返回到父片段