在Android上,绑定服务与启动服务的区别以及如何同时使用两者。

9
我正在提出一个棘手的问题,这个问题已经在这里这里部分得到了解决(在我看来)。比如说,我们想创建一个音乐应用程序,使用(比方说)一个活动和一个服务。我们希望当活动停止或销毁时,服务能够持续存在。这种生命周期建议使用启动服务:

当应用程序组件(如活动)通过startService()调用启动服务时,服务就会“启动”。一旦启动,即使启动它的组件被销毁,服务也可以无限期地在后台运行。

好的,但是我们还想能够与服务通信,所以我们需要一个服务绑定。没问题,正如这个答案所建议的,我们既有绑定服务,也有启动服务。

到目前为止还不错,但问题在于当活动启动时,我们不知道服务是否存在。它可能已经启动,也可能没有启动。答案可能是这样的:

  • 在启动时,尝试绑定服务(使用bindService(),不使用BIND_AUTO_CREATE标志)
  • 如果失败,则使用startService()启动服务,然后再绑定它。

这个想法基于对bindService()文档的特定阅读:

连接到应用程序服务,如有需要则创建它。

如果零标志表示“实际上不需要服务”,那么我们就没问题了。所以我们尝试使用以下代码来实现:

private void connectToService() {
    Log.d("MainActivity", "Connecting to service");
    // We try to bind to an existing service
    Intent bindIntent = new Intent(this, AccelerometerLoggerService.class);
    boolean bindResult = bindService(bindIntent, mConnection, 0);
    if (bindResult) {
        // Service existed, so we just bound to it
        Log.d("MainActivity", "Found a pre-existing service and bound to it");
    } else {
        Log.d("MainActivity", "No pre-existing service starting one");
        // Service did not exist so we must start it

        Intent startIntent = new Intent(this, AccelerometerLoggerService.class);
        ComponentName startResult = startService(startIntent);
        if (startResult==null) {
            Log.e("MainActivity", "Unable to start our service");
        } else {
            Log.d("MainActivity", "Started a service will bind");
            // Now that the service is started, we can bind to it
            bindService(bindIntent, mConnection, 0);
            if (!bindResult) {
                Log.e("MainActivity", "started a service and then failed to bind to it");
            } else {
                Log.d("MainActivity", "Successfully bound");
            }
        }
    }
}

每次我们得到的都是成功的绑定:
04-23 05:42:59.125: D/MainActivity(842): Connecting to service
04-23 05:42:59.125: D/MainActivity(842): Found a pre-existing service and bound to it
04-23 05:42:59.134: D/MainActivity(842): onCreate

全局的问题是“我是否误解了绑定和启动服务以及如何使用它们?”更具体的问题是:
  • 正确理解文档的方式是否是认为传递给bindService()的零标志意味着“不要启动服务”?如果不是,是否没有办法调用bindService()而不启动服务?
  • 为什么bindService()即使服务没有运行也会返回true?在这种情况下,基于Log调用,似乎服务没有被启动。
  • 如果前面的观点是bindService()的正确/预期行为,是否有解决方法(例如,确保只有在服务未运行时才调用startService)?

P.S. 我已经解决了自己代码中的问题:我无论如何都会发出startService()调用,因为重复的startService()会被忽略。但是,我仍然希望更好地理解这些问题。


我不完全理解这是如何工作的,但是这个这个或许可以帮到你。 - Ivan Black
1个回答

2
  1. 如果您使用0标志绑定服务,则该服务将不会启动。您可以使用BIND_AUTO_CREATE标志绑定服务,如果服务未启动,则会启动服务。但是,当您取消绑定服务时,服务将被销毁。
  2. 使用0标志绑定服务始终返回true。
  3. 您始终可以调用startService。如果服务已经在运行,则不会创建新的服务。将调用正在运行的服务onStartCommand。

如果您在onCreate中启动startService,然后在onResume中绑定bindService,并在onPause中解除绑定unbindService,则不应该有任何问题。


我认为这也是有问题的,因为如果用户按下返回键,您的活动将被销毁。在我们的音乐播放器示例中,即使用户按下返回键,我们也希望音乐继续播放。 - angelatlarge
只要您不调用stopService,您的音乐应该会继续播放。 - Hoan Nguyen
但是下一次显示Activity时,startService()将从onCreate()中调用,我们又回到了同样的问题。 - angelatlarge
@HoanNguyen 我有一个已经启动的服务,稍后将其绑定到一个活动(与启动服务的相同活动)。我使用IBinder中的服务实例调用服务中的函数来播放歌曲等。当我按返回按钮时,歌曲停止了,但服务没有停止。为什么歌曲会停止?谢谢。 - Amit0191
你必须发布一个带有你的代码的问题,因为有很多事情可能发生,没有代码就无法回答。 - Hoan Nguyen
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接