Android文档建议,要从活动到托管片段进行通信,片段可以定义回调接口,并要求主机活动实现它。基本模式涉及在片段中实现onAttach
,并将活动转换为回调接口。请参阅http://developer.android.com/guide/components/fragments.html#CommunicatingWithActivity。
这是一个为片段提供一些初始化数据以及监听导航回调的示例。
public class HostActivity extends Activity implements FragmentHost {
@Override
UiModel getUiModel() {
return mUiModel;
}
@Override
FragmentNavListener getNavListener() {
return mNavListener;
}
...
}
public class HostedFragment extends Fragment {
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
if (activity instanceof FragmentHost) {
FragmentHost host = (FragmentHost) activity;
setUiModel(host.getUiModel());
setNavListener(host.getFragmentNavListener());
}
}
...
}
将此与在主机活动中使用onAttachFragment
进行比较,以显式初始化片段:
public class HostActivity extends Activity {
@Override
public void onAttachFragment(Fragment fragment) {
super.onAttachFragment(fragment);
if (fragment instanceof HostedFragment) {
HostedFragment hostedFragment = ((HostFragment) fragment);
hostedFragment.setUiModel(mUiModel);
hostedFragment.setNavListener(mNavListener);
}
}
...
}
对我来说,似乎第一种模式有一些缺点:
对于那些已经完成碎片通信活动的人,您认为哪种模式更可取,为什么?从主机活动中使用onAttachFragment
是否存在缺陷?
答案 0 :(得分:6)
我不能亲自谈论测试,但有片段/活动回调接口通信的替代方案。
例如,您可以使用事件总线来分离片段和活动。这里有一个很棒的活动巴士:
Square正在积极开发一些非常有才华的工程师。 您还可以使用Android支持库中打包的LocalBroadcastManager。
来自广场的Eric Burke有一个演讲,他提到了两个可以在这里找到的地方:
答案 1 :(得分:2)
我在上一个项目中使用了Fragment.onAttach(...)
模式。我看到两个好处:
为了利用2.,您不能像在代码示例中那样存储对UiModel
和NavListener
的引用。相反,只要您想要与这些实例进行交互,就应该使用((FragmentHost) getActivity).getNavListener().onNav(this)
或((FragmentHost) getActivity).onNav(this)
之类的代码。如果要避免常量转换,可以将片段主机存储在onDetach(...)
中设置为空的字段中作为中间接地方法。
我同意从创建它的活动初始化片段似乎更直观。
说了这么多,我将在我当前的项目中完全跳过片段。以下帖子很好地反映了我上一篇文章的经验教训:https://corner.squareup.com/2014/10/advocating-against-android-fragments.html
答案 2 :(得分:1)
更新:根据最新指南,我们应该使用 sharedViewModel 类在片段和活动之间进行通信。
但是,如果您不使用 viewModel 并使用回调,您仍然应该考虑删除 onAttachFragment 回调,因为它现在已被弃用。
在 onAttachFragment 上,建议的方法是使用 addFragmentOnAttachListener 向与该事务关联的 fragmentManager 添加侦听器。
请看下面的例子:
childFragmentManager.addFragmentOnAttachListener { _, fragment ->
if (fragment is RetryDialogFragment) {
//Do your work here.
}
}
您还应该注意添加此侦听器的位置。您很可能希望在执行片段事务之前添加此侦听器,并且应确保添加的侦听器不会超过一次。