Android 服务中的广播接收器:设计问题

Android 服务中的广播接收器:设计问题,android,service,broadcastreceiver,restart,Android,Service,Broadcastreceiver,Restart,我的应用程序需要收听广播事件(耳机事件)并相应地采取行动。我发现耳机事件不能通过minifest接收器使用,因为该事件启用了标志“接收器注册”。因此,您只能在程序中动态注册此事件。由于我的应用程序在事件期间不会处于活动状态,我需要一个服务来处理此事件,因此我在onCreate中注册,并在onDestroy中注销。到目前为止,一切顺利。我实现了该服务并开始测试它,我发现在资源短缺的情况下,该服务可能会被系统终止,系统将自动重新启动该服务。然而,令人惊讶的是,终止和重启之间的延迟是完全随机的,可能是

我的应用程序需要收听广播事件(耳机事件)并相应地采取行动。我发现耳机事件不能通过minifest接收器使用,因为该事件启用了标志“接收器注册”。因此,您只能在程序中动态注册此事件。由于我的应用程序在事件期间不会处于活动状态,我需要一个服务来处理此事件,因此我在onCreate中注册,并在onDestroy中注销。到目前为止,一切顺利。我实现了该服务并开始测试它,我发现在资源短缺的情况下,该服务可能会被系统终止,系统将自动重新启动该服务。然而,令人惊讶的是,终止和重启之间的延迟是完全随机的,可能是巨大的。有时是几秒钟,有时是几小时。因此,当广播事件发生时,您永远无法确保您的服务正在运行

我浏览了stackoverflow网站,了解到有各种各样的建议。如果有一个不执行任何操作的虚拟线程,这将增加服务的“重要性”,请将服务与startForeground一起使用,这将导致通知。所有这些看起来都是权宜之计,并非万无一失

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


谢谢。

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

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

已知的解决方案和解决方法: stack overflow中已经给出了几个答案,这些答案关注于如何确保您的服务不会首先被终止。其中最重要的是让服务在前台启动。请参见此处,了解如何执行此操作。这会在服务启动时发出通知。在前台启动服务可以确保它几乎永远不会被终止。还有其他建议的方法,比如从您的服务生成一个持续运行的线程(这个线程不需要做任何事情)。这应该会提高线程的“重要性”,并且服务不会经常被终止。但是,我怀疑这可能会耗尽电池电量

我发现的新解决方案: 我发现了另一种规避此问题的方法,它不需要前台服务或电池耗尽线程。当intent为null时,您只需要在onStartCommand中调用服务中的startService()(即,这是服务的系统重新启动,假设服务create在前面返回START_)。调用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;
    }

}
如果您有一个更复杂的场景,即您正在通过intent向服务传递参数,并且您正在使用START\u REDELIVER\u intent,那么在调用startService()之前,您可能需要使用“标志”来发现重新启动,并在intent中重新创建其他参数


为我工作。希望这能有所帮助。

我在startForeground方面运气不错。这就是说,它可能不是万无一失的,但对我来说它是相当万无一失的。你要注册什么耳机活动?@Catherine:谢谢你的评论。“startForeground”会不会给最终用户造成混乱的通知?@HoanNguyen我正在注册android.intent.action.HEADSET\u插件也许你也应该注册AudioManager.action\u AUDIO\u变得嘈杂