startForeground如何去除通知栏

写app的时候经常希望某个service可以常驻内存,但是在系统内存低的时候还是不可避免的被杀掉,为了降低被杀掉的概率,一般的解决方式是通过startForeground()service设置成前台运行。但是从android 5.0开始,前台运行的service必须在通知栏有一个常驻通知,点都点不掉,试想一下如果每个app都在通知栏有一个常驻通知的恐怖场景。。。

startForeground如何去除通知栏_第1张图片

那么有没有办法去除掉这个常驻通知呢?答案是肯定的,需要用一些tricky的办法。

首先写一个BootstarpService,顾名思义,这个service只是起引导作用,干完活就退出了。最精华的部分其实就是这句stopSelf(),说白了这个service其实还没起起来就被停掉了,这样onDestroy()里就会调用stopForeground(),通知栏的常驻通知就会被消掉。

public class BootstrapService extends Service {
    @Override
    public void onCreate() {
        super.onCreate();
        startForeground(this);
        // stop self to clear the notification
        stopSelf();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        stopForeground(true);
    }

    public static void startForeground(Service context) {
        NotificationManager nm = (NotificationManager) context.getSystemService(NOTIFICATION_SERVICE);
        NotificationCompat.Builder builder = new NotificationCompat.Builder(context);
        builder.setContentTitle("I'm running")
                .setContentText("")
                .setWhen(System.currentTimeMillis())
                .setPriority(Notification.PRIORITY_MIN)
                .setSmallIcon(R.drawable.notification_icon)
                .setAutoCancel(true);
        Notification notification = builder.build();

        context.startForeground(8888, notification);
    }
}

接下来写我们的主service,主service会先调用一次startForeground(),然后再启动BootstrapService

public class MainService extends Service {
    @Override
    public void onCreate() {
        super.onCreate();
        BootstrapService.startForeground(this);
        // start BootstrapService to remove notification
        Intent intent = new Intent(this, BootstrapService.class);
        startService(intent);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        stopForeground(true);
    }
}

看到这里大家应该已经明白了,说白了就是两个service共用一个notification ID,第一个service起来的时候会显示通知栏,然后第二个service停掉的时候去除通知栏。

最后再double confirm一下主service是前台运行的:

root@hammerhead:/ # dumpsys activity services | grep xinxin
  * ServiceRecord{f393843 u0 com.xinxin.startforeground/.MainService}
    intent={cmp=com.xinxin.startforeground/.MainService}
    packageName=com.xinxin.startforeground
    processName=com.xinxin.startforeground
    baseDir=/data/app/com.xinxin.startforeground-1/base.apk
    dataDir=/data/user/0/com.xinxin.startforeground
    app=ProcessRecord{6af09dd 22261:com.xinxin.startforeground/u0a122}
isForeground=true foregroundId=8888 foregroundNoti=Notification(pri=-2 contentView=com.xinxin.startforeground/0x1090085 vibrate=null sound=null defaults=0x0 flags=0x72 color=0x00000000 vis=PRIVATE)

可以看到isForeground=true,主service是不受影响的。

说到底我觉得这应该算是个漏洞,我要是google工程师给每个notification加个reference count你就跪得笔挺挺的...不过不管怎么说,目前这个方法还是能够解决问题的。

源码下载

你可能感兴趣的:(Android应用)