【问题标题】:Bind service to activity or fragment?将服务绑定到活动或片段?
【发布时间】:2014-06-19 14:42:08
【问题描述】:

我正在开发一个音乐播放器应用程序。我有一个主要活动,它有多个片段,每个片段都在设备专辑、艺术家等方面显示歌曲。
我有一个音乐服务可以处理所有播放和其他内容。
我感到困惑的是该服务与我拥有的各种片段的绑定。
现在我正在将主要活动和每个片段单独与服务绑定,它的工作非常好。但我想知道这是否真的是最佳实践?有什么方法可以将主要活动与服务绑定,然后在其子片段中使用它?
我可能错过了一些非常基本的活动或片段或服务概念。所以请有人在这方面指导我。
我想这更像是一个概念性问题,因此不需要任何代码。但是,如果需要,请告诉我。

编辑:
我的问题是:将服务与具有多个子片段(每个子片段都将使用该服务)的活动绑定的更好方法是什么?

【问题讨论】:

  • 将其绑定到托管您的片段的活动。片段采用宿主活动的上下文,可通过 getActivity() 方法访问。然后,您可以通过活动与服务进行交互。试图绑定到每个片段和活动是一团糟。
  • @Rarw 感谢您的建议。这是唯一的方法还是有任何替代方法?
  • 我想这可能会有所帮助:stackoverflow.com/questions/15235773/…

标签: android android-fragments android-service


【解决方案1】:

Service 绑定到您的活动,而不是Fragment。您的应用程序的描述,一个具有多个Fragment 的活动被换入和换出,这使得这是最(也是唯一)实用的方法。

当您将Service 绑定到Activity 时,您将其生命周期绑定到Activity 的生命周期。 Bound Services。每次您在活动中添加或删除Fragment 时,都会创建和销毁Fragment。您不想尝试将服务链接到此进程,因为这样每次创建或销毁新片段时您都必须创建和销毁服务。

而是绑定到主机Activity。然后,您可以使用访问绑定服务的接口或通过Intent 从片段与主机活动进行交互。

【讨论】:

  • 是否应该创建 Fragments 的构造函数,包括后端服务的实例?
  • 这取决于它是否对您的片段正常工作至关重要。这通常是我向构造函数添加内容时的规则。
  • 如果你有多个片段并且每个片段都绑定到同一个服务,那么绑定的服务将一直保持到至少一个客户端被绑定。如果您也将您的活动绑定到服务,那么您可以确定只要活动存在,服务就会一直运行。根据我的经验,直接绑定到 Fragments 是最好的选择,我会发布一个答案。
  • @Ena 该问题描述了一个加载/交换多个片段以控制在后台服务中运行的功能的活动。所有片段都由同一个活动托管。在这种情况下,将活动绑定到服务,然后加载活动中的每个片段(在视觉上我认为它就像一个倒置的金字塔,没有中间活动,片段就不能存在)是有意义的。如果我有多个活动和多个片段,我会根据您描述的原因单独绑定片段。
【解决方案2】:

我认为更简洁的架构是直接从片段绑定。关于 Rarw 的回答中概述的问题,您也可以从您的活动和片段中绑定到服务。这样,您就可以确定服务将一直存在,直到活动没有被破坏。

我可以看到从片段连接的两个主要优点:

  1. 服务连接是异步的,因此在片段内部,您永远无法确定您从活动中获得的服务不为空。这将引导您至少进行一些空指针检查,以及在片段创建时和服务连接时刷新片段的某种机制(因此,无论两者中的哪一个先发生,您都可以确定您将显示数据)。

  2. 您不依赖于片段所在的特定活动。要从活动中获取服务,我认为您正在对活动特定类进行强制转换。您可以使用getBoundService 之类的方法创建一个类似BoundActivity 的接口以从中获取服务,但考虑到第1 点的优势,我认为这是一种开销。如果您有多个服务怎么办。

    李>

更新

这是一个非常简单的项目来展示这一点。 https://github.com/ena1106/FragmentBoundServiceExample

【讨论】:

  • 是的,你的第一个理由很对!!我一直在收到 NullPointerExceptions。特别是当第一个片段加载并且活动尚未绑定到服务时。感谢您发布简单的项目链接。我会立即尝试绑定到片段。希望它有效! ;)
  • 我认为这应该是公认的答案。这类问题的答案是“视情况而定”。所以我相信如果将它放在活动的片段中有意义的话,一定要这样做。
【解决方案3】:

您可以通过getActivity()从片段中访问您的活动

【讨论】:

  • 感谢您的快速回复。我知道这个功能。但我想问的是,是否建议仅将服务与主要活动绑定并在片段中使用 getActivity() 来使用该服务?还是应该将它与所有活动和片段单独绑定?
  • 我会绑定到尽可能少的实体,尽管我不知道这是否可取。
  • getActivity() 可以返回 null。最好使用 onAttach(),参考 stackoverflow.com/a/11743728/763176
  • getActivity 将返回正在使用该片段的任何父活动。因此它不保证活动是什么类型。
【解决方案4】:

您可以在此库中使用事件总线模式,即事件总线发布/订阅模式。https://github.com/greenrobot/EventBus查看项目站点以获取更多信息。

您可以从/向服务发送事件到活动或片段

【讨论】:

  • 虽然我真的不需要这么多的功能,但我肯定会看看这个库。谢谢。
【解决方案5】:

如果您需要在片段生命周期开始时从服务获取一些数据到片段,则 onServiceConnected 活动还不能被调用,主要是在您旋转设备时,您将获得 NPE。 我认为让 Fragment 建立自己的连接是个好主意,因为该服务是使用 startService() 而不是 bindService() 启动的。

【讨论】:

    【解决方案6】:

    我在 My Host Activity 中绑定服务,并通过参数中设置的 Bundle 传递 Ibinder 的对象。

    我的代码可能是这样的:

    private ServiceConnection mConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            //put service in bundle
        }
    
        @Override
        public void onServiceDisconnected(ComponentName name) {
    
        }
    };
    

    【讨论】:

      【解决方案7】:

      我发现唯一可靠的方法是Fragment中使用加载器

      1. 在片段中创建Loader
      2. 使用Loadercontext(在调用Fragment 的onCreate 时,在initLoader 中设置为activity
      3. onStartLoading 中绑定服务,使用ServiceConnection,在服务绑定后立即调用forceLoad()
      4. 可选地在onStartLoading/onStopLoading中注册回调
      5. 解绑onStopLoading中的服务

      【讨论】:

        猜你喜欢
        • 2010-12-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-04-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多