我正在尝试确定绑定(bind)服务是否适合在我的应用程序中执行后台工作。要求是各种应用程序组件可以通过它发出不同优先级的 Web 请求。 (因此该服务必须维护某种队列,并能够取消它对其他更高优先级的持续请求)。我希望该服务对用户来说相对不显眼,这样他们在完成应用程序后就不会发现它正在运行 - 如果我想做一些更重要的事情,在应用程序关闭时继续,我可以使用 startForeground( ) 在此过程中推送通知。
解决方案一:从activity绑定(bind)
因此,对于给定的应用程序组件,它应该能够绑定(bind)到服务以完成工作。但是似乎有一个众所周知的问题,如果 Activity 正在执行绑定(bind),则在配置更改(轮换)期间绑定(bind)将丢失,因为 Activity 将关闭。
所以,我想我可以使用我创建的另一个上下文 (new Context()
) 并将其绑定(bind)到服务,然后使用非 UI fragment 在配置中维护此上下文更改,直到我认为我完成了它。我只能在配置更改期间或作为 Activity 绑定(bind)的永久替代方法来执行此操作。 (我可能应该指出,这是一种标准的 recommended 方式来维护跨配置更改的实例)
解决方案 2:
我看到的主要替代方案是我可以使用应用程序上下文来进行绑定(bind)——但这会持续太久吗?和/或应用上下文和服务之间是否存在某种循环关系,从而防止服务和应用上下文被破坏?
问题:
所以我想对自己回答的问题是:我应该使用第一种方法(具有临时上下文的 Activity )吗?还是第二种(只需将服务绑定(bind)到应用上下文)?
我认为应用程序上下文可以多次绑定(bind)到服务然后解除绑定(bind)的次数是否正确? (即,您可以在每个上下文中拥有多个有效绑定(bind))?
在第一个解决方案中使用我自己的上下文 (new Context()
) 会导致任何问题吗?
编辑
找到更多信息:https://groups.google.com/forum/#!topic/android-developers/Nb58dOQ8Xfw
似乎也很难任意“创建”上下文,因此解决方案 1 和 2 的组合似乎是合适的,其中服务连接在配置更改期间保持不变,但绑定(bind)到应用程序上下文。我仍然担心从应用程序上下文中解除绑定(bind)两次的可能性。我自己对绑定(bind)进行计数似乎是不必要的——任何人都可以确认/否认绑定(bind)是每个连接而不是每个上下文吗?
最佳答案
所以在做了一些挖掘之后,我想我已经想出了一个(到目前为止)未经测试的解决方案。
首先,根据黛安在这里的建议:https://groups.google.com/forum/#!topic/android-developers/Nb58dOQ8Xfw我应该绑定(bind)到应用程序上下文——这样我丢失上下文的问题就消失了——我可以在使用非 UI fragment 更改的配置中维护我的 ServiceConnection——太好了。然后,当我完成后,我可以使用应用程序上下文交还服务连接并解除绑定(bind)。我不应该收到任何泄漏的服务连接警告。 (我可能应该指出,这是一种标准的 recommended 方式来维护跨配置更改的实例)
这个问题的最后一个症结是我不确定我是否可以从同一个上下文中多次绑定(bind)——关于绑定(bind)的文档暗示绑定(bind)和上下文的生命周期之间存在某种依赖性,所以我担心我必须做我自己的引用计数形式。我查看了源代码并在此处结束:http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.4.2_r1/android/app/LoadedApk.java#LoadedApk.forgetServiceDispatcher%28android.content.Context%2Candroid.content.ServiceConnection%29
至关重要的是,这些行:
sd = map.get(c);
if (sd != null) {
map.remove(c);
sd.doForget();
if (map.size() == 0) {
mServices.remove(context);
}
显示 map
正在用于我担心的引用计数。
所以带回家是这样的:
- 绑定(bind)的服务将在应用程序上下文中正常工作,我们应该这样做以防止在配置更改期间将服务连接从一个 Activity 泄漏到另一个 Activity
- 我可以在非 UI fragment 上安全地保持我的服务连接,并在完成后使用它解除绑定(bind)
我会尝试尽快发布一些经过测试的代码。
更新和测试解决方案:我已经编写了一些代码来测试它并在此处发布:https://github.com/samskiter/BoundServiceTest
它似乎工作得很好,非 ui fragment (数据 fragment )在旋转变化期间充当一个很好的代理监听器以捕获来自服务的结果(监听器的目的是将请求紧密绑定(bind)到 UI为了保证它保持响应。显然,任何模型更改都可以通过观察者传播到 UI。)
编辑:我认为我应该明确回答 OP 中的问题...
我应该使用第一种方法(具有临时上下文的 Activity )吗?还是第二个(只需将服务绑定(bind)到应用程序上下文)? 第二个
我认为应用程序上下文可以多次绑定(bind)到服务然后解除绑定(bind)的次数是否正确? (即,您可以在每个上下文中拥有多个有效绑定(bind))? 是
在第一个解决方案中使用我自己的上下文 (new Context()) 会不会导致任何问题? 这甚至是不可能的
最后的总结:
这种模式应该非常强大 - 我可以优先处理来 self 应用程序中各种来源的网络 IO(或其他任务)。我可以有一个前台 Activity 来制作用户要求的一些小 io,同时我可以启动一个前台服务来同步我所有的用户数据。前台服务和 Activity 都可以绑定(bind)到同一个网络服务以完成它们的请求。
所有这一切,同时确保服务只在需要的时候存在 - 即它与 android 很好地配合。
我很高兴能尽快将其应用到应用中。
更新:我已经尝试将其写下来,并在此处的博客条目中为更广泛的后台工作问题提供一些背景信息:http://blog.airsource.co.uk/2014/09/10/android-bound-services/
关于java - 从新上下文绑定(bind)到服务以进行配置更改或从应用程序上下文绑定(bind)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24312016/