在保持唤醒锁定和调用startForeground之后服务被杀死

时间:2011-06-11 18:13:16

标签: java android android-service

我遇到了一个问题,我的服务被杀了,即使我拿着唤醒锁,我已经打电话给 startForeground 。当平板电脑(华硕Transformer TF101)发生这种情况时,停止服务而不调用onDestroy 。没有其他可见的应用程序,日志cat没有显示任何异常(没有'内存不足'消息等)。在被杀之后,服务立即重新启动。

我正在开发的应用程序是一个聊天客户端,需要一个持续的连接,它也是基于插件的,所以我的应用程序是这样开发的:客户端 - 主机服务 - 多个子服务'。

主机服务是粘滞的,持有唤醒锁并调用startForeground(并显示通知),子服务不粘,不持有唤醒锁并且是后台服务。

如果客户端本身是打开的,则问题不会发生,但我要使用的模型是用户可以使用该设备并保持连接(接收消息等),而无需始终打开客户端本身。

任何人都可以提供任何解释,说明为什么服务会以这种方式被杀死,如果是这样可以防止它发生?当聊天客户端显示用户登录和注销时,并且服务死亡会终止所有打开的连接,这会使聊天客户端“反弹”。目前,它似乎发生在每15到45分钟之间。

此外,如果有人知道如何在整个连接时间内没有按住唤醒锁定的情况下连续打开套接字连接,我很乐意听到它!

主机服务源的修剪测试用例版本如下。

public class HostService extends Service
{
    PowerManager m_powerManager = null;
    PowerManager.WakeLock m_wakeLock = null;

    @Override
    public IBinder onBind( Intent intent )
    {
        return m_serviceImplementation;
    }

    @Override
    public void onCreate()
    {
        super.onCreate();       
    }

    @Override
    public void onDestroy()
    {
        if( m_wakeLock != null )
        {
            m_wakeLock.release();
            m_wakeLock = null;
        }

        stopForeground( true );

        super.onDestroy();
    }

    @Override
    public int onStartCommand( Intent intent, int flags, int startId )
    {
        // Display a notification about us starting. We put an icon in the
        // status bar.
        Notification notification = createNotification();

        startForeground( R.string.service_running, notification );

        if( m_powerManager == null )
        {
            m_powerManager = (PowerManager)getSystemService(Context.POWER_SERVICE);
        }

        if( m_wakeLock == null )
        {
            m_wakeLock = m_powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Keep background services running");
            m_wakeLock.acquire();
        }

        // We want this service to continue running until it is explicitly
        // stopped, so return sticky.
        return START_STICKY;
    }

    /**
     * Create a notification to show the service is running
     */
    private Notification createNotification()
    {
        CharSequence text = getText( R.string.service_running );
        CharSequence title = getText( R.string.app_name );

        // The PendingIntent to launch our activity if the user selects this
        // notification
        PendingIntent contentIntent = PendingIntent.getActivity( this, 0, new Intent(this, MainChat.class) , 0 );

        Notification notification = new Notification( android.R.drawable.sym_action_chat, title, System.currentTimeMillis() );  
        notification.setLatestEventInfo( this, title, text, contentIntent );

        return notification;
    }

    private final IMessageInterface.Stub m_serviceImplementation = new IMessageInterface.Stub()
    {
        ...
    };
}

Android Manifest(相关位):

<uses-sdk android:minSdkVersion="11" android:targetSdkVersion="11" />

<service android:name="com.mydomain.chatClient.server.HostService" android:exported="true" android:enabled="true" android:process=":remote"/>

<uses-permission android:name="android.permission.WAKE_LOCK" />

1 个答案:

答案 0 :(得分:9)

  

我遇到的问题是我的服务被杀死了,即使我拿着唤醒锁并且我已经调用了startForeground。

startForeground()降低了服务被杀的可能性,但并不能阻止它。

  

我正在开发的应用程序是一个聊天客户端,需要一个持续的连接,它也是基于插件的,所以我的应用程序是这样开发的:客户端 - 主机服务 - 多个子服务'。

我建议摆脱其中一个图层。即使操作系统没有关闭您,许多用户也会(例如,任务杀手,在设置中运行服务),考虑到您运行的服务太多了。

  

如果客户端本身是打开的,则问题不会发生,但我要使用的模型是用户可以使用该设备并保持连接(接收消息等),而无需始终打开客户端本身。

我建议选择这个。你可能认为它很性感。你的一些用户会因为浪费电池而攻击你。

  

任何人都可以提供任何解释,说明为什么服务会以这种方式被杀死,如果是这样可以防止它发生?

我首先要摆脱android:process=":remote"。你不需要它。你不想要它。你可能会伤到自己,因为它可能会加速Android对摆脱你服务的兴趣。你绝对是在用它来伤害用户,因为你没有充分的理由浪费RAM。

然后,如果您将这些插件实现为单独的应用程序,我将摆脱插件。在这种情况下,每个都将在自己的进程中运行,浪费更多的RAM。此外,您当前的实现会有缺陷,因为您不会使用com.mydomain.chatClient.server.HostService来分隔“什么是service在内部命名为“和”由其他希望使用它的单独安装的应用程序调用的服务“。如果你没有将插件作为单独的应用程序实现,那么我就看不到将它们放在单独的服务中的价值,而不是将它们全部折叠到一个服务中。

  

此外,如果有人知道如何在整个连接时间内没有按住唤醒锁定的情况下连续打开套接字连接,我很乐意听到它!

如果套接字是使用无线数据而不是WiFi,则不需要<intent-filter>。套接字将保持打开状态,该套接字上的传入数据包将唤醒您的代码。此时,您需要获取WakeLock足够长的时间,以便您在数据到达时执行任何操作,然后释放WakeLock

如果您使用的是WiFi,这个技巧不起作用,因此需要WakeLock(可能还有WakeLock)。