Android Service startForeground() 可能不显示Notification问题

Android中的Service分前台服务和后台服务两类:

前台服务会在通知栏有一条不能被手动清除的Notification,当此前台服务由于内存不足而被系统kill掉的时候,此Notification也会同时消失,用户由此得知此服务已经停止了,起到一个通知用户服务是否还在工作;

后台服务则没有类似的Notification,即使被系统kill掉,用户也不会得到什么通知。

Service通过调用方法 startForeground (int id, Notification notification)方法设置是否为前台任务,如:

		Notification notification = new Notification(R.drawable.icon, getText(R.string.ticker_text),
		        System.currentTimeMillis());
		Intent notificationIntent = new Intent(this, ViewServerActivity.class);
		PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
		notification.setLatestEventInfo(this, getText(R.string.notification_title,
		getText(R.string.notification_message), pendingIntent);
		startForeground(ONGOING_NOTIFICATION, notification);

由此代码引发了一个需要特别注意的事情,代码片段中的NOGOING_NOTIFICATION的值,不能是0,否则就不会显示出Notification,究其原因只能看源码了:

service startForeground()和stopForeground()源码:

    public final void startForeground(int id, Notification notification) {
        try {
            mActivityManager.setServiceForeground(
                    new ComponentName(this, mClassName), mToken, id,
                    notification, true);
        } catch (RemoteException ex) {
        }
    }

    public final void stopForeground(boolean removeNotification) {
        try {
            mActivityManager.setServiceForeground(
                    new ComponentName(this, mClassName), mToken, 0, null,
                    removeNotification);
        } catch (RemoteException ex) {
        }
    }

可见是有mActivityManager.setServiceForeground()里面做了封装,mActivityManager是一个IActivityManager接口的实现类,此接口实现类的关系具体参考此博文:

http://blog.csdn.net/stonecao/article/details/6579710

其实最终运行到的是ActiveServices类中的setServiceForegroundLocked方法:

public void setServiceForegroundLocked(ComponentName className, IBinder token,
            int id, Notification notification, boolean removeNotification) {
        final int userId = UserHandle.getCallingUserId();
        final long origId = Binder.clearCallingIdentity();
        try {
            ServiceRecord r = findServiceLocked(className, token, userId);
            if (r != null) {
                if (id != 0) {
                    if (notification == null) {
                        throw new IllegalArgumentException("null notification");
                    }
                    if (r.foregroundId != id) {
                        r.cancelNotification();
                        r.foregroundId = id;
                    }
                    notification.flags |= Notification.FLAG_FOREGROUND_SERVICE;
                    r.foregroundNoti = notification;
                    r.isForeground = true;
                    r.postNotification();
                    if (r.app != null) {
                        updateServiceForegroundLocked(r.app, true);
                    }
                    getServiceMap(r.userId).ensureNotStartingBackground(r);
                } else {
                    if (r.isForeground) {
                        r.isForeground = false;
                        if (r.app != null) {
                            mAm.updateLruProcessLocked(r.app, false, false);
                            updateServiceForegroundLocked(r.app, true);
                        }
                    }
                    if (removeNotification) {
                        r.cancelNotification();
                        r.foregroundId = 0;
                        r.foregroundNoti = null;
                    }
                }
            }
        } finally {
            Binder.restoreCallingIdentity(origId);
        }
    }
至此,我们应该很清楚了,如果传进来的id=0,则直接执行以下代码了:

 if (removeNotification) {
         r.cancelNotification();
         r.foregroundId = 0;
         r.foregroundNoti = null;
 }
最后直接cancleNotification(),所以传id=0,就相当于取消notification显示!

从google上的文档看到以下参数说明:

Parameters
id The identifier for this notification as per NotificationManager.notify(int, Notification); must not be 0.
notification The Notification to be displayed.

但是在我的eclipse中的javadoc却是看不到“must not be 0”的说明的!


根据提供的引用内容,当使用`Context.startForegroundService()`启动服务后,必须在服务的`onCreate()`方法中调用`Service.startForeground()`方法,否则会报错`android.app.RemoteServiceException: Context.startForegroundService() did not then call Service.startForeground()`。这是因为在Android O(API级别26)及更高版本中,启动前台服务需要调用`startForeground()`方法来显示通知,以确保服务在后台运行时不会被系统杀死。 以下是一个示例代码,演示如何正确使用`Service.startForeground()`方法: ```java public class MyService extends Service { private static final int NOTIFICATION_ID = 1; @Override public void onCreate() { super.onCreate(); // 创建通知 Notification notification = new Notification.Builder(this) .setContentTitle("Foreground Service") .setContentText("Service is running in the foreground") .setSmallIcon(R.drawable.ic_notification) .build(); // 将服务设置为前台服务 startForeground(NOTIFICATION_ID, notification); } @Override public int onStartCommand(Intent intent, int flags, int startId) { // 执行服务的逻辑操作 return START_STICKY; } @Override public void onDestroy() { super.onDestroy(); // 停止前台服务 stopForeground(true); } @Nullable @Override public IBinder onBind(Intent intent) { return null; } } ``` 在上述示例中,我们在服务的`onCreate()`方法中创建了一个通知,并调用`startForeground()`方法将服务设置为前台服务。在服务的`onDestroy()`方法中,我们调用`stopForeground(true)`方法停止前台服务。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值