5

我有一个在单独进程中运行的服务。我发现在主进程 UI 线程从 onDestroy() 退出后,我的服务正在被销毁,即使我已经为应用程序上下文提供了绑定并指定了 BIND_AUTO_CREATE。

在我的主进程的 UI 线程 onCreate() 我有这个绑定代码:

Intent intent = new Intent(mAppContext, MyService.class);
mAppContext.bindService(intent, mMyServiceConnection, Context.BIND_AUTO_CREATE);

在我的主进程的 UI 线程 onDestroy() 我有这个解绑代码:

mAppContext.unbindService(mMyServiceConnection);

请注意,我从不调用 stopService()。

Android 的 bindService() 文档说:

只要调用上下文存在,系统就会认为该服务是必需的。

如果我没看错的话,因为我提供了应用程序的上下文,所以系统认为该服务在应用程序的整个生命周期内都是必需的。

我认为应用程序的上下文可能会随着 onDestroy() 而消失。这就是 Android 的文档对 getApplicationContext() 所说的:

返回当前进程的单个全局应用程序对象的上下文。

如果应用程序的上下文因 onDestroy() 而死,那么我认为 Android 有一个大问题。问题在于,当显示器旋转时,会调用 onDestroy()(并立即调用 onCreate())。因此,效果是当显示器旋转时 - 在我的情况下它经常发生!-- 我的服务总是退出。

请注意,我的应用程序进程的 pid 永远不会改变,即它是同一个进程。鉴于 getApplicationContext() 的文档说明“当前进程”,这一点很重要。

以下是我的调试日志显示的内容:

04-03 05:15:12.874: DEBUG/MyApp(841): 主 onDestroy
04-03 05:15:12.895: DEBUG/MyApp(847): 服务 onUnbind
04-03 05:15:12.895: DEBUG/MyApp(847 ): service onDestroy
04-03 05:15:12.934: DEBUG/MyApp(841): main onCreate
04-03 05:15:12.966: DEBUG/MyApp(847): service onCreate
04-03 05:15:12.975: DEBUG /MyApp(847): 服务绑定

所以我的问题是:

1)我对绑定/解除绑定的理解是否正确?

2) 有没有办法让我的服务在调用 UI 线程的 onDestroy() 时不被破坏?

问题 #2 的一个技巧是永远不要解除绑定。但我不喜欢它,因为每次调用 onDestroy() 时我都会泄漏一个绑定。我可以“记住”我有一个泄露的绑定,并且只泄露了那个,但是我有级联的黑客攻击,它真的很难看。

4

3 回答 3

4

1)是的,我认为你的理解是正确的(我说我认为是因为我认为我理解你在说什么;-))。您使用的标志的意思是“如果有人试图绑定它并保持它运行,只要有人绑定它就会自动启动这个服务,但是一旦没有人绑定它,就可以随意杀死它”。

2)查看此处START_STICKY描述的标志。这应该允许您启动服务并使其保持运行,无论调用发生什么Context

一般来说,onDestroy()意味着您的活动即将被终止。当您旋转显示时,将Activity被杀死并重新创建。您有责任以Bundle适当的方法将任何状态保存到 中,然后将其恢复到 中onCreate()

于 2011-04-03T06:14:45.553 回答
0

您的服务是否被杀死:

  1. Activity如果堆栈上有第二个?
  2. 如果您处理配置更改?

为什么在你的应用程序被销毁后你需要你的服务保持活跃?

我认为一般的经验法则是您无法确定您的活动和服务何时会被终止。如果这阻碍了您想要实现的目标,那么可能有一个聪明的方法可以解决它。

编辑- 您实际上可以处理方向配置更改,以便您的活动不会重新启动。有关更多信息,请参阅此答案的后半部分。

关于“第二个” Activity:图像你开始活动A,然后活动B。现在您在显示时旋转屏幕B,导致B重新启动。此时会A重新启动吗?我不确定,但我有一种预感,A在方向更改期间,它往往会保持活力并让您的应用程序保持活力。如果这是您的目标,这可能是保持服务活力的另一种策略。

于 2011-04-03T06:33:03.433 回答
0

只有当以下两个都为真时,服务才会被销毁:

  1. 所有对 bindService() 的调用都与对 unbindService() 的相应调用相匹配。
  2. 如果有人调用了 startService(),有人也调用了 stopService() 或服务调用了 stopSelf()。

服务既可以启动,也可以绑定连接。在这种情况下,只要服务已启动或有一个或多个使用 Context.BIND_AUTO_CREATE 标志的连接,系统就会保持服务运行。一旦这两种情况都不成立,就会调用服务的 onDestroy() 方法并有效地终止服务。

这提供了一个很好的解决方案,它也是相当正确和安全的!

假设有 2 个活动(在此示例中为“查看器”和“聊天”)需要服务,如果两者都有 bindService 和 startService。他们还使用活页夹在 onStart 和 onStop 期间更新“viewer_connected”和“chat_connected”。

然后服务在执行此操作的线程中运行一个循环:

public isRunning = true;
while (isRunning) {

    if (viewer_connected) {
        // send update to viewer activity
    }

    if (chat_connected) {
        // send update to chat activity
    }

    try {
        Thread.sleep(5000);
    } catch (Exception e) { isRunning=false; }

    // 3 second timeout before destroying service
    if (!viewer_connected && !chat_connected) {
        try { Thread.sleep(3000); } catch (Exception e) { isRunning=false; }

        if (!viewer_connected && !chat_connected) isRunning=false;
    }

}
stopSelf();

这是有效的,因为它需要在销毁服务之前取消绑定活动和服务 stopself(),这意味着在服务被销毁之前存在超时。

于 2016-03-17T15:28:33.860 回答