Android:旋转显示时服务被破坏

时间:2011-04-03 06:08:06

标签: android service oncreate ondestroy

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

在我的主进程'UI thread onCreate()中,我有这个绑定代码:

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

在我的主进程'UI thread onDestroy()中,我有这个无法解释的代码:

mAppContext.unbindService(mMyServiceConnection);

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

Android的bindService()文档说:

  

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

如果我正确阅读,因为我提供了应用程序的上下文,系统认为该服务在应用程序的生命周期内是必需的。

我原以为应用程序的上下文可能会与onDestroy()一起消失。这就是Android的文档对getApplicationContext()所说的:

  

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

如果应用程序的上下文死于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):service onBind

所以我的问题是:

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

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

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

3 个答案:

答案 0 :(得分:4)

1)是的,我认为你的理解是正确的(我说我想是因为我认为我理解你在说什么;-))。您正在使用的标志意味着“如果有人试图绑定它并且只要有人绑定它就会自动启动它,但是一旦没有人绑定它,就可以自由地杀死它”。

2)按照here所述查看START_STICKY标志。这应该允许您启动服务并使其保持运行,无论调用Context

发生什么

一般情况下,onDestroy()表示您的活动即将被杀死。旋转显示时,Activity将被终止并重新创建。您有责任在适当的方法中将任何州保存到Bundle,然后在onCreate()中恢复。

答案 1 :(得分:0)

您的服务是否被杀死:

  1. 如果堆栈上有第二个Activity
  2. 如果您处理配置更改?
  3. 为什么您的应用程序被销毁后需要您的服务才能保持活力?

    我认为一般的经验法则是您无法确定何时会杀死您的活动和服务。如果这阻碍了你想要实现的目标,可能会有一个聪明的方法。

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

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

答案 2 :(得分:0)

只有满足以下两个条件时,服务才会被销毁:

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

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

    这提供了一个非常正确和安全的好解决方案!

    假设有两个活动(在本例中为'viewer'和'chat')需要服务,如果是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(),这意味着在服务被销毁之前存在超时。