2

我的应用程序需要监听广播事件(HEADSET 事件)并采取相应措施。我发现 HEADSET 事件不能通过 minifest 接收器使用,因为该事件启用了标志 FLAG_RECEIVER_REGISTERED_ONLY。因此,您只能在程序中动态注册此事件。由于我的应用程序在事件期间不会处于活动状态,因此我需要一个服务来处理此事件,我在 onCreate 中注册并在 onDestroy 中取消注册。到目前为止,一切都很好。我实现了服务并开始测试,我发现服务可以在资源紧缩的情况下被系统杀死,系统会自动重启服务。然而,令人惊讶的是,kill 和 restart 之间的延迟是完全随机的,并且可能是巨大的。有时是几秒钟,有时是几小时。所以,

我浏览了stackoverflow,有各种建议。有一个什么都不做的虚拟线程,这将增加服务的“重要性”,使用带有 startForeground 的服务 - 这会导致通知。所有这些看起来都是变通办法,并非万无一失。

有没有办法以万无一失的方式解决这个问题?处理“REGISTERED_ONLY”广播事件的替代解决方案是什么?

谢谢。

4

1 回答 1

6

我做了很多试验和错误编程,并找到了解决方案。所以,我回答我自己的问题。

服务重启时的 Android 行为: 众所周知,Android 服务可以在资源紧张的情况下被系统强制停止。Android 会自动重启该服务。这是不可避免的,您需要对服务进行编程以优雅地处理这种情况。请注意,服务强制停止和重新启动之间存在延迟。这种延迟似乎是随机的,可能以数小时为单位。我发现这种延迟是有规律的。在第一次强制停止后,Android 会在 5000 毫秒(5 秒)内重新启动应用程序。此外,如果在第一次重启后 60 秒内再次强制停止服务(第二次),Android 会将下次重启的延迟更新 4 次(即 5000 x 4 = 20000ms = 20 秒)。20 秒后,Android 再次重启服务(第三次)。如果在 60 秒内再次强制停止服务(第三次),第三次重启后延迟更新为 4 次 20000 ms = 80000 ms = 80 秒,以此类推。因此,如果您的服务在自动重启后的 60 秒内被强制终止,则延迟会呈指数级增长(5 秒、20 秒、80 秒、320 秒、1280 秒……)。如果您的服务在 60 秒内没有再次被强制终止,则延迟计时器将重置为 5 秒以进行下一次强制停止并重新启动。在我看来,超过 20 秒的重启计时器是不合理的,如果您甚至不确定您的服务是否正在运行,程序员应该如何使用服务编写可靠的应用程序?如果您的服务在自动重启后的 60 秒内被强制终止,则延迟呈指数级增长(5 秒、20 秒、80 秒、320 秒、1280 秒……)。如果您的服务在 60 秒内没有再次被强制终止,则延迟计时器将重置为 5 秒以进行下一次强制停止并重新启动。在我看来,超过 20 秒的重启计时器是不合理的,如果您甚至不确定您的服务是否正在运行,程序员应该如何使用服务编写可靠的应用程序?如果您的服务在自动重启后的 60 秒内被强制终止,则延迟呈指数级增长(5 秒、20 秒、80 秒、320 秒、1280 秒……)。如果您的服务在 60 秒内没有再次被强制终止,则延迟计时器将重置为 5 秒以进行下一次强制停止并重新启动。在我看来,超过 20 秒的重启计时器是不合理的,如果您甚至不确定您的服务是否正在运行,程序员应该如何使用服务编写可靠的应用程序?

已知的解决方案和变通方法: 堆栈溢出中已经有几个答案,重点是如何确保您的服务一开始就不会被杀死。其中最重要的是让服务在前台启动。请参阅此处以了解如何执行此操作。这会在服务启动时引起通知。在前台启动服务可确保它几乎不会被杀死。还有其他建议的方法,例如从您的服务中生成一个连续运行的线程(该线程不必做任何事情)。这应该提高线程的“重要性”,并且服务不会经常被杀死。但是,我怀疑这可能会耗尽电池。

我发现的新解决方案: 我发现了另一种绕过此问题的方法,它不需要前台服务或电池耗尽线程。当意图为空时,您只需在 onStartCommand 的服务中调用 startService() (即,这是服务的系统重新启动,假设服务创建之前返回了 START_STICKY)。当您调用 startService() 时,重新启动计时器延迟始终重置为 5 秒。下面的示例

public class MyService extends Service {

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) 
    {
        if( null == intent )
        {
            Log.d( "MyServiceTag", "This is a System Restart");
            /* restart the service with startService().
             * This will ensure that the delay between system force-stop and restart  
             * is always 5 seconds
             */
            startService( new Intent( getBaseContext(), MyService.class));
        }

        return START_STICKY;
    }


    @Override
    public void onDestroy()
    {
        Log.d( "MyServiceTag", "In onDestroy");
    }


    @Override
    public IBinder onBind(Intent intent) {
        // TODO Auto-generated method stub
        return null;
    }

}

如果您有一个更复杂的场景,您通过意图将参数传递给您的服务并且您正在使用 START_REDELIVER_INTENT,您可能需要使用“标志”来发现重新启动并在调用 startService 之前在您的意图中重新创建附加参数()。

为我工作。希望这可以帮助。

于 2013-04-26T14:08:58.990 回答