START_STICKY,前台 Android 服务消失,恕不另行通知

发布于 2024-11-19 04:08:56 字数 4061 浏览 5 评论 0原文

我已经在我的新应用程序中启动了一项服务。该服务位于前台,并带有通知。当它在 AVD 2.1 API Level 7 中运行时,一切正常。但是,当它在运行 Gingerbread 的三星 Galaxy Tab 上运行时,该服务将启动(图标和应用程序名称出现在通知区域的顶部),但几秒钟后,该服务就会消失。我可以看到的日志中的最后一个条目与我的应用程序相关联,是我的 Log.d("Taglines","Returning with " + START_STICKY) 的结果,它紧接在 "return START_STICKY ;" 之前在我的服务的 onStartCommand 覆盖中,如下所示:

@Override
public int onStartCommand(Intent intent, int flags, int startId) {

    int rc ;
    Log.d("Taglines","onStartCommand()");
    Toast.makeText(this, "Starting service TagsManager", Toast.LENGTH_SHORT).show();
    Log.d("Taglines","Calling super.onStartCommand()");
    rc = super.onStartCommand(intent,flags,startId);
    Log.d("Taglines","super.onStartCommand return code was " + rc);
    createNotification(INITIAL_NOTIFICATION_TEXT);
    Log.d("Taglines","Returning with " + START_STICKY);
    return START_STICKY ;
}

通知设置如下:

void createNotification(String text) {

    Log.d("Taglines","createNotification called");
    if (mNotificationManager == null) {
        // Get a reference to the Notification Manager
        String ns = Context.NOTIFICATION_SERVICE;
        mNotificationManager = (NotificationManager) getSystemService(ns);
        Log.d("Taglines","Obtained reference to Notification Manager");
    }

    // Instantiate the Notification
    int icon = R.drawable.ic_notification;
    CharSequence tickerText = "Taglines";
    long when = System.currentTimeMillis();

    notification = new Notification(icon, tickerText, when);

    // Define Notification's expanded message and intent
    Log.d("Taglines","createNotificacion() .. getApplicationContext");
    context = getApplicationContext();
    contentText = text;
    // notificationIntent = new Intent(this, TagsOverview.class);
    notificationIntent = new Intent(this, TagsServiceMenu.class);
    contentIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);

    notification.setLatestEventInfo(context, contentTitle, contentText, contentIntent);

    // Pass the Notification to the NotificationManager: 
    Log.d("Taglines","createNotificacion() ... passing notification");
    mNotificationManager.notify(NOTIFICATION_ID, notification);
    Log.d("Taglines","Starting foreground");
    startForeground(NOTIFICATION_ID, notification);
    Log.d("Taglines","Started");
}

这是服务启动时“adb logcat”的结果:

D/Taglines(21863): Starting service
D/Taglines(21863): TagsManager(nullary) completed
D/Taglines(21863): onStartCommand()
D/Taglines(21863): Calling super.onStartCommand()
D/Taglines(21863): super.onStartCommand eturn code was 2
D/Taglines(21863): createNotification called
D/Taglines(21863): Obtained reference to Notification Manager
D/Taglines(21863): createNotificacion() .. getApplicationContext
D/Taglines(21863): createNotificacion() ... passing notification
D/Taglines(21863): Starting foreground
D/Taglines(21863): Started
D/Taglines(21863): Returning with 1

之后,没有什么特别的(PID 21863 没有任何东西)。只是一堆:

D/KeyguardViewMediator(  302): setHidden false
D/KeyguardViewMediator(  302): setHidden false
D/KeyguardViewMediator(  302): setHidden false
D/KeyguardViewMediator(  302): setHidden false
D/KeyguardViewMediator(  302): setHidden false
W/InputManagerService(  302): Window already focused, ignoring focus gain of:         com.android.internal.view.IInputMethodClient$Stub$Proxy@40bc06e8
D/KeyguardViewMediator(  302): setHidden false
D/KeyguardViewMediator(  302): setHidden false
D/KeyguardViewMediator(  302): setHidden false
D/KeyguardViewMediator(  302): setHidden false
D/KeyguardViewMediator(  302): setHidden false
D/KeyguardViewMediator(  302): setHidden false
D/KeyguardViewMediator(  302): setHidden false
D/KeyguardViewMediator(  302): setHidden false
D/KeyguardViewMediator(  302): setHidden false

我认为在这种情况下不需要它,但这是 AndroidManifest.xml 的相关部分:

    <service android:name=".TagsManager"
             android:exported="false">
    </service>

我可能在哪里出错了?我还可以提供哪些其他信息?

I have started a service in my new application. The service is foregrounded, with a Notification. When this is run in the AVD 2.1 API Level 7, all works fine. But when it's run on a Samsung Galaxy Tab running Gingerbread, the service will start (the icon and app name appear at the top of the notification area), but after a few seconds, the service disappears. The last entry in the Log that I can see is associated with my App, is the result of my Log.d("Taglines","Returning with " + START_STICKY), which immediately precedes "return START_STICKY ;" in my Service's onStartCommand override, as follows:

@Override
public int onStartCommand(Intent intent, int flags, int startId) {

    int rc ;
    Log.d("Taglines","onStartCommand()");
    Toast.makeText(this, "Starting service TagsManager", Toast.LENGTH_SHORT).show();
    Log.d("Taglines","Calling super.onStartCommand()");
    rc = super.onStartCommand(intent,flags,startId);
    Log.d("Taglines","super.onStartCommand return code was " + rc);
    createNotification(INITIAL_NOTIFICATION_TEXT);
    Log.d("Taglines","Returning with " + START_STICKY);
    return START_STICKY ;
}

The notification is set like this:

void createNotification(String text) {

    Log.d("Taglines","createNotification called");
    if (mNotificationManager == null) {
        // Get a reference to the Notification Manager
        String ns = Context.NOTIFICATION_SERVICE;
        mNotificationManager = (NotificationManager) getSystemService(ns);
        Log.d("Taglines","Obtained reference to Notification Manager");
    }

    // Instantiate the Notification
    int icon = R.drawable.ic_notification;
    CharSequence tickerText = "Taglines";
    long when = System.currentTimeMillis();

    notification = new Notification(icon, tickerText, when);

    // Define Notification's expanded message and intent
    Log.d("Taglines","createNotificacion() .. getApplicationContext");
    context = getApplicationContext();
    contentText = text;
    // notificationIntent = new Intent(this, TagsOverview.class);
    notificationIntent = new Intent(this, TagsServiceMenu.class);
    contentIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);

    notification.setLatestEventInfo(context, contentTitle, contentText, contentIntent);

    // Pass the Notification to the NotificationManager: 
    Log.d("Taglines","createNotificacion() ... passing notification");
    mNotificationManager.notify(NOTIFICATION_ID, notification);
    Log.d("Taglines","Starting foreground");
    startForeground(NOTIFICATION_ID, notification);
    Log.d("Taglines","Started");
}

This is the result from "adb logcat" when the service is started:

D/Taglines(21863): Starting service
D/Taglines(21863): TagsManager(nullary) completed
D/Taglines(21863): onStartCommand()
D/Taglines(21863): Calling super.onStartCommand()
D/Taglines(21863): super.onStartCommand eturn code was 2
D/Taglines(21863): createNotification called
D/Taglines(21863): Obtained reference to Notification Manager
D/Taglines(21863): createNotificacion() .. getApplicationContext
D/Taglines(21863): createNotificacion() ... passing notification
D/Taglines(21863): Starting foreground
D/Taglines(21863): Started
D/Taglines(21863): Returning with 1

After that, nothing special (nothing at all from PID 21863). Just a bunch of:

D/KeyguardViewMediator(  302): setHidden false
D/KeyguardViewMediator(  302): setHidden false
D/KeyguardViewMediator(  302): setHidden false
D/KeyguardViewMediator(  302): setHidden false
D/KeyguardViewMediator(  302): setHidden false
W/InputManagerService(  302): Window already focused, ignoring focus gain of:         com.android.internal.view.IInputMethodClient$Stub$Proxy@40bc06e8
D/KeyguardViewMediator(  302): setHidden false
D/KeyguardViewMediator(  302): setHidden false
D/KeyguardViewMediator(  302): setHidden false
D/KeyguardViewMediator(  302): setHidden false
D/KeyguardViewMediator(  302): setHidden false
D/KeyguardViewMediator(  302): setHidden false
D/KeyguardViewMediator(  302): setHidden false
D/KeyguardViewMediator(  302): setHidden false
D/KeyguardViewMediator(  302): setHidden false

I don't think it's needed in this case, but here's the relevant portion of the AndroidManifest.xml:

    <service android:name=".TagsManager"
             android:exported="false">
    </service>

Where might I have gone wrong? What other information can I provide?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

半仙 2024-11-26 04:08:56

有几件事:

  1. 摆脱mNotificationManager.notify(NOTIFICATION_ID, notification);startForeground() 为您显示通知图标。

  2. 前台 Service 仍然可以被杀死,只是可能性较小。

  3. 2.3 中有一个错误(不确定是否已修复),当 Service 被终止并重新启动时,其 onStartCommand() 将不会再次调用。相反,您必须在 onCreate() 中进行任何设置。

A few things:

  1. Get rid of the mNotificationManager.notify(NOTIFICATION_ID, notification);. startForeground() displays the notification icon for you.

  2. Foreground Services can still be killed, they're just less likely to be.

  3. There's a bug in 2.3 (not sure if it was fixed yet) where when a Service is killed and restarted, its onStartCommand() will NOT be called again. Instead you're going to have to do any setting up in onCreate().

锦上情书 2024-11-26 04:08:56

这两段代码仅在手机内存不足并在完成执行之前终止 Service 时相关。 START_STICKY 告诉操作系统在拥有足够内存后重新创建服务,并以空意图再次调用 onStartCommand()START_NOT_STICKY 告诉操作系统不必再次重新创建服务。还有第三个代码 START_REDELIVER_INTENT 告诉操作系统重新创建 Service 并将相同的意图重新传递给 onStartCommand()

本文,作者:Dianne Hackborn比官方文档更好地解释了这个背景。

这里的关键部分是函数返回的新结果代码,告诉系统如果服务进程在运行时被终止,应该如何处理该服务:

START_STICKY 与之前的行为基本相同,其中
服务保持“启动”状态,稍后将由系统重新启动。
该平台与之前版本的唯一区别是
如果由于进程被终止而重新启动,则 onStartCommand()
将在具有 null Intent 的服务的下一个实例上调用
而不是根本不被调用。使用此模式的服务应该
请务必检查这种情况并进行适当处理。

START_NOT_STICKY 表示,从 onStartCreated() 返回后,如果
该进程被终止,没有剩余的启动命令可以传递,
那么服务将被停止而不是重新启动。这使得
对于仅在以下情况下运行的服务更有意义
执行发送给他们的命令。例如,可以启动一个服务
从警报起每 15 分钟轮询一次网络状态。如果得到
在做这项工作时被杀,最好就让它这样
停止并在下次警报响起时开始。

START_REDELIVER_INTENT 类似于 START_NOT_STICKY,除非
服务进程在调用给定的 stopSelf() 之前被终止
意图,该意图将被重新传递给它,直到它完成
(除非经过多次尝试后它仍然无法完成,在
系统放弃的点)。这对于以下服务很有用
收到要做的工作的命令,并希望确保他们这样做
最终完成每个发送命令的工作。

Both codes are only relevant when the phone runs out of memory and kills the Service before it finishes executing. START_STICKY tells the OS to recreate the service after it has enough memory and call onStartCommand() again with a null intent. START_NOT_STICKY tells the OS to not bother recreating the service again. There is also a third code START_REDELIVER_INTENT that tells the OS to recreate the Service AND redelivery the same intent to onStartCommand().

This article by Dianne Hackborn explained the background of this a lot better then the official documentation.

The key part here is a new result code returned by the function, telling the system what it should do with the service if its process is killed while it is running:

START_STICKY is basically the same as the previous behavior, where the
service is left "started" and will later be restarted by the system.
The only difference from previous versions of the platform is that it
if it gets restarted because its process is killed, onStartCommand()
will be called on the next instance of the service with a null Intent
instead of not being called at all. Services that use this mode should
always check for this case and deal with it appropriately.

START_NOT_STICKY says that, after returning from onStartCreated(), if
the process is killed with no remaining start commands to deliver,
then the service will be stopped instead of restarted. This makes a
lot more sense for services that are intended to only run while
executing commands sent to them. For example, a service may be started
every 15 minutes from an alarm to poll some network state. If it gets
killed while doing that work, it would be best to just let it be
stopped and get started the next time the alarm fires.

START_REDELIVER_INTENT is like START_NOT_STICKY, except if the
service's process is killed before it calls stopSelf() for a given
intent, that intent will be re-delivered to it until it completes
(unless after some number of more tries it still can't complete, at
which point the system gives up). This is useful for services that are
receiving commands of work to do, and want to make sure they do
eventually complete the work for each command sent.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文