服务正在重新创建者AlarmManager [英] Service being re-Created by AlarmManager

查看:160
本文介绍了服务正在重新创建者AlarmManager的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有,我想通过报警来触发一个相当标准的服务。下面是该服务的启动部分:

I have a fairly standard Service which I wish to trigger using an alarm. Here's the initiation section of the service:

class MyService extends Service {
    private Context context;
    private AlarmManager  alarmManager = null;

    private final String startReason = "com.stuff.myreason";
    private final int REASON_NO_INTENT = 0;
    private final int REASON_ALARM     = 1;
    private final int REASON_X         = 2; // and so on.

    @Override
    void onCreate() {
        super.onCreate();
        context = getApplicationContext();
        alarmManager = (AlarmManager)getSystemService(ALARM_SERVICE);
        // do onCreate stuff
    }

    @Override
    int onStartCommand (Intent intent, int flags, int startId) {
        int reason = REASON_NO_INTENT;
        if (intent != null) {
            reason = intent.getExtra(startReason, REASON_NO_INTENT);
        }

        switch(reason) {
            // handle the different reasons we may have been "started"
        }

        return START_STICKY;
    }
}

当我触发使用context.startService一项活动,它开始绝对正常。特别是,如果它已经运行它不(再)从头开始,而只是进入通过 onStartCommand现有实例()。这是预期的行为。然而,当我触发它使用AlarmManager:

When I trigger it using context.startService from an activity, it starts absolutely normally. In particular, if it is already running it doesn't (re)start from scratch but simply enters the existing instantiation via onStartCommand(). This is the expected behaviour. However, when I trigger it using the AlarmManager:

Intent intent = new Intent(context, MyService.class);
intent.putExtra(purposeOfStartCode, REASON_ALARM);

PendingIntent pi = PendingIntent.getService(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);

alarmManager.set(AlarmManager.RTC_WAKEUP, /* A time in the future */, pi);

当报警是因为它似乎重新从头服务:它启动一个新实例,调用的onCreate()然后 onStartCommand( ),而不是仅仅调用 onStartCommand()在已经运行的实例。

When the alarm is due it seems to restart the service from scratch: it starts a new instantiation, calls onCreate() and then onStartCommand() rather than just calling onStartCommand() in the already running instantiation.

我已经试图改变 PendingIntent 标志 FLAG_ONE_SHOT 和替换上下文 MyService.this 无改善。

I have already tried changing the PendingIntent flag to FLAG_ONE_SHOT and replacing context with MyService.this with no improvement.

我相当困惑本 - 任何人都可以解释这种现象,并建议如何得到它像预期的那样

I am rather bemused by this - can anyone explain this behaviour and suggest ways to get it to behave as expected?

编辑 - 行动,导致解决方案的集合是我的回答如下

EDIT - The collection of actions that resulted in a solution are in my answer below.

推荐答案

经过一番调查和工作,我发现了一些东西。做完所有的人,这个问题看起来像它的消失了:

After some investigation and work, I've discovered a number of things. Having done all of them, this problem looks like it's disappeared:

  1. 如果您覆盖ONSTART和onStartCommand在服务(以允许旧设备),你把super.onStartCommand在后,它会调用ONSTART,这意味着你会得到每一个意图来了两次!

  1. If you override onStart and onStartCommand in a service (to allow for older devices) and you put super.onStartCommand in the latter, it will call onStart, meaning you get every intent coming in twice!

作为每个其他的答案(和在其上的评论),所述AlarmManager设计并指定提供广播意图,而不是其他类型之一。然而,在实践中,它是不挑剔,似乎兑现的其他形式。我认为这是解决问题的关键之一。

As per one of the other answers (and comments on it), the AlarmManager is designed and specified to deliver Broadcast intents, not other types. However, in practice, it isn't picky and seems to honour other forms. I think that this was one of the keys in resolving the issue.

如果该服务是在同一进程中的其他activites等,服务有时似乎一下就重新启动。这可能是在这一问题指出,问题的实际原因。请参阅<一href="http://stackoverflow.com/questions/7211066/android-service-oncreate-is-called-multiple-times-without-calling-ondestroy">Android服务的onCreate被多次调用,而无需调用的onDestroy 。

If the service is in the same process as other activites etc, the service sometimes seems to "just get restarted". This may be the actual cause of the issue noted in this question. See Android service onCreate is called multiple times without calling onDestroy.

事情似乎只时使用意图与服务,而不是绑定和使用Messenger或绑定和访问方式进行沟通更稳定。虽然两者都是正确的,他们是相当复杂的管理(虽然你可以使用这种方法:<一href="http://stackoverflow.com/questions/15413667/what-is-the-$p$pferred-way-to-call-an-android-activity-back-from-a-service-thread/15414328#15414328">What是preferred方法来调用一个Android活动回从服务线程和<一href="http://stackoverflow.com/questions/4208886/using-the-android-application-class-to-persist-data">Using Android的应用程序类,以保持数据)。虽然我完全AP preciate了Android的文档不同意我,以我的观察移动广播意图仅通信显得关键。如果你去为单独的进程的方法,你将不得不反正要做到这一点。

Things seem to be more stable when solely using intents to communicate with the Service rather than binding and using a Messenger or binding and accessing methods. Whilst both of these are correct, they are quite complex to manage (although you could use this approach: What is the preferred way to call an Android Activity back from a Service thread and Using the Android Application class to persist data). Whilst I fully appreciate that the android docs disagree with me, in my observation moving to broadcast intent only communication seemed key. If you go for the separate process approach you'll have to do this anyway.

它支付是如何声明一致,解决你的类。这是一个有点乱,但是,因为它有时似乎是付费使用全名(com.company.superapp.CleverService),而不是短期(CleverService或.CleverService)。因此,它可能会更好,始终使用全名。

It pays to be consistent in how you declare and address your classes. It's a bit messy, but, because it sometimes seems to pay to use full names ("com.company.superapp.CleverService") rather than short ("CleverService" or ".CleverService"). So, it's probably better to always use full names.

拇指漂浮在那里大约上下文(使用getApplicationContext)的规则不是真正正确的方式来做到这一点。请参阅<一href="http://stackoverflow.com/questions/7298731/when-to-call-activity-context-or-application-context/7298955#7298955">When调用活动上下文或应用程序上下文?;在本质上利用这一点,除非你真的需要使用一个更广阔的背景,并管理好你的变量。

The rule of thumb floating around out there about contexts ("use getApplicationContext") isn't really the right way to do it. See When to call activity context OR application context?; in essence use this, unless you really need to use a broader context, and manage your variables well.

这是可能的垃圾收集清理的东西仍然在使用,如果它是一个活动,服务,螺纹,AsyncTask的,等这已不再是围绕创建。如果应用程序是基于一个服务,它可能是明智的类副本进来,使他们没有得到后及时清理。

It's possible for the garbage collector to clear up something still in use if it was created in an Activity, Service, Thread, AsyncTask, etc that is no longer around. If the application is based around a service, it may be wise to make a copy of classes coming in so that they don't get cleared up later.

一个更简洁的方式开始比通常认为服务是给服务的IntentFilter的与它的全名作为动作。然后,您可以创建的意图,只用类名作为字符串启动它。这意味着你不必担心环境。请参见问题的呼叫服务

A neater way to start a service than is often suggested is to give the service an intentFilter with it's full name as the action. You can then create the intent to start it with just the class name as a string. This means you don't have to worry about context. See Issue in Calling Service.

这篇关于服务正在重新创建者AlarmManager的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆