是否最好使用 Activity.onAttachFragment 或 Fragment.onAttach 在 Activity 和嵌套片段之间进行通信?
Posted
技术标签:
【中文标题】是否最好使用 Activity.onAttachFragment 或 Fragment.onAttach 在 Activity 和嵌套片段之间进行通信?【英文标题】:Is it preferable to use Activity.onAttachFragment or Fragment.onAttach to communicate between an Activity and a nested fragment? 【发布时间】:2012-10-05 17:21:12 【问题描述】:android 文档建议,要从 Activity 与托管 Fragment 进行通信,该 Fragment 可以定义一个回调接口并要求宿主 Activity 实现它。基本模式涉及在您的片段中实现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);
...
在我看来,第一种模式似乎有一些缺点:
-
它使片段更难在不同的活动中使用,因为
因为所有这些活动都必须实现所需的接口。我可以想象给定片段实例不需要完全由宿主 Activity 配置,但所有潜在宿主 Activity 都需要实现宿主接口的情况。
对于不熟悉所用模式的人来说,这会使代码更难理解。在 onFragmentAttached 中初始化片段似乎更容易理解,因为初始化代码位于创建片段的同一类中。
使用像 Robolectric 这样的库进行单元测试变得更加困难,因为在调用 onAttach 时,您现在必须实现 FragmentHost 而不仅仅是调用 onAttach(new Activity()。
对于那些从事过分散交流活动的人,您认为哪种模式更可取,为什么?在宿主活动中使用onAttachFragment
有什么缺点吗?
【问题讨论】:
【参考方案1】:我不能亲自谈论测试,但片段/活动回调接口通信有替代方案。
例如,您可以使用事件总线来解耦片段和您的活动。可以在此处找到出色的事件总线:
Otto - An event Bus by Square
Square 的一些非常有才华的工程师正在积极开发它。 您还可以使用打包在 Android 支持库中的 LocalBroadcastManager。
LocalBroadcastManager
来自 Square 的 Eric Burke 有一个演示文稿,他提到了这两个可以在这里找到:
Android App Anatomy
【讨论】:
Otto 现已弃用 LocalBroadcastManager 已弃用 developer.android.com/reference/androidx/localbroadcastmanager/… 并推荐此 developer.android.com/training/basics/fragments/communicating【参考方案2】:更新:根据最新指南,我们应该使用 sharedViewModel 类在片段和活动之间进行通信。
但是,如果您不使用 viewModel 并使用回调,您仍然应该考虑移除 onAttachFragment 回调,因为它已被弃用。
建议的方法是使用 addFragmentOnAttachListener 向与该事务关联的 fragmentManager 添加一个侦听器,而不是 onAttachFragment。
请看下面的例子:
childFragmentManager.addFragmentOnAttachListener _, fragment ->
if (fragment is RetryDialogFragment)
//Do your work here.
您还应该注意添加此侦听器的位置。您很可能希望在执行片段事务之前添加此侦听器,并且应确保您不会多次添加该侦听器。
【讨论】:
在导航组件的情况下应该在哪里使用这个监听器?我用导航组件设置了 BottomNavigationView,并在 BaseActivity 的 onCreate() 中实现了这个监听器。第一次调用片段 onAttach() 时,此侦听器会通知,但下次我手动调用 onAttach() 时,侦听器不会通知。你能帮助我吗?提前致谢 手动调用 onAttach() 是什么意思?我对导航组件不太熟悉,但为了获得通知,您必须使用添加了“addFragmentOnAttachListener”的相同“fragmentManager”进行片段事务。 我有一个场景,点击片段内的按钮后需要重新加载片段。这发生正确并导致再次调用 onAttach() 方法,但侦听器不会再次收到回调。 尝试在 *** 上将其作为一个单独的问题提出,其中包含您如何添加和重新加载片段的代码。【参考方案3】:我在上一个项目中使用了Fragment.onAttach(...)
模式。我看到了两个优点:
-
您可以尽早检查托管活动是否实现了所需的接口,如果没有则抛出异常
在分离片段后保留宿主上下文引用的风险较小
为了利用 2.,您不能像在代码示例中那样存储对 UiModel
和 NavListener
的引用。相反,每当您想与这些实例交互时,您应该使用类似((FragmentHost) getActivity).getNavListener().onNav(this)
的代码,或者((FragmentHost) getActivity).onNav(this)
。如果您想避免持续转换,您可以将片段主机存储在您在 onDetach(...)
中设置为 null 的字段中作为中间方法。
我同意从创建片段的 Activity 中初始化片段看起来更直观。
说了这么多,我将在我当前的项目中完全跳过片段。下面的帖子很好地反映了我上一篇的经验教训:https://corner.squareup.com/2014/10/advocating-against-android-fragments.html
【讨论】:
以上是关于是否最好使用 Activity.onAttachFragment 或 Fragment.onAttach 在 Activity 和嵌套片段之间进行通信?的主要内容,如果未能解决你的问题,请参考以下文章
[Java]判断Integer值相等最好不用==最好使用equals
是否可以在不使用 ObjectDataSource 的情况下自定义 GridView(在 ASP.NET 中,最好是 3.5)分页?
html 您是否经常将Flash文件嵌入到html页面中?如果是,您最好保存下面的有效Flash嵌入代码以备将来使用。