美文网首页android开发知识点高级UI
Service隐藏Notification和简单保活操作

Service隐藏Notification和简单保活操作

作者: 晓风残月酒醒 | 来源:发表于2019-11-13 15:15 被阅读0次

    其实在前面我写的《Notification相关操作》文章里面提了一嘴这个事情,Android 8.0以后启动Service需要采用context.startForegroundService(intent)的形式启动,而这个操作会导致一个Service必须启动一个Notification的问题,如果被要求隐藏这个Notification的话就需要采取一些特殊手段了:

    判定Service是否正在后台运行的工具类:

    import android.app.ActivityManager;
    import android.content.Context;
    
    public class ServiceUtil {
        /**
         * @param context
         * @return
         */
        public static boolean isServiceRunning(String strServiceName, Context context) {
            ActivityManager manager = (ActivityManager) context.getSystemService(context.ACTIVITY_SERVICE);
            for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
                if (strServiceName.equals(service.service.getClassName())) {
                    return true;
                }
            }
            return false;
        }
    }
    

    Service本身还是在8.0以上启动一个Notification,不过启动之后马上删除通道,这样就能隐藏Notification了

    import android.app.Service;
    import android.app.NotificationChannel;
    import android.content.Intent;
    import android.os.Handler;
    import android.os.IBinder;
    import android.app.Notification;
    import android.app.NotificationManager;
    import android.app.PendingIntent;
    import android.content.Context;
    import android.graphics.BitmapFactory;
    import android.os.Build;
    import android.os.Looper;
    import android.support.v4.app.NotificationCompat;
    
    public class BuySellService extends Service {
        private final IBinder binder = new BuySellBinder();
        private NotificationManager manager = null;                                 // 通知管理器
        private String notificationChannelId = "channel_1";                         // Android8.0以后展示通知需要注册的通道编号
        private String notificationChannelName = "channel_name_1";                  // Android8.0以后展示通知需要注册的通道名称
        private Context context;                                                    // 上下文对象
        private static final int notification_id = 198564;                          // 状态栏 notification 对象的编号
        private Handler handler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
            }
        };
    
        @Override
        public void onCreate() {
            super.onCreate();
            context = BuySellService.this;
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                showNotification();
            }
        }
    
       @Override
        public IBinder onBind(Intent intent) {
            return binder;
        }
    
        public class BuySellBinder extends Binder {
            public BuySellService getService() {
                return BuySellService.this;
            }
        }
    
        // 展示Notification的方法
        private void showNotification() {
            if (Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
                // 创建渠道
                createNotificationChannel();
                // 展示通知
                showHighNotification();
            }/** else {
                // 展示通知
                showSimpleNotification();
            }**/
        }
    
        // Android8.0以前的版本使用此方法启动Notification
        private void showSimpleNotification() {
            Notification notification = new NotificationCompat.Builder(context, notificationChannelId)
                    .setContentTitle("买卖客户端")
                    .setContentText("正在运行中...")
                    /**点击事件监听器**/
                    .setContentIntent(PendingIntent.getBroadcast(context, 0, new Intent(ConstantValues.FOREGROUND_NOTIFICATION_CLICKED), 0))
                    /**消失的监听器**/
                    .setDeleteIntent(PendingIntent.getBroadcast(context, 0, new Intent(ConstantValues.FOREGROUND_NOTIFICATION_DISMISS), 0))
                    .setLargeIcon(BitmapFactory.decodeResource(context.getResources(), R.mipmap.ic_launcher))
                    .setSmallIcon(R.mipmap.ic_launcher) //设置小图标,4.x在右边,5.x在左边
                    /**通知产生的时间,会在通知信息里显示**/
                    .setWhen(System.currentTimeMillis())
                    /**设置该通知优先级**/
                    .setPriority(Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.JELLY_BEAN ? NotificationCompat.PRIORITY_MAX : Notification.PRIORITY_MAX)
                    /**设置这个标志当用户单击面板就可以让通知将自动取消**/
                    .setAutoCancel(false)
                    /**设置他为一个正在进行的通知。他们通常是用来表示一个后台任务,用户积极参与(如播放音乐)或以某种方式正在等待,因此占用设备(如一个文件下载,同步操作,主动网络连接)**/
                    .setOngoing(true)
                    /**向通知添加声音、闪灯和振动效果的最简单、最一致的方式是使用当前的用户默认设置,使用defaults属性,可以组合:**/
                    /**.setDefaults(Notification.DEFAULT_VIBRATE or Notification.DEFAULT_SOUND)**/
                    .build();
            notification.flags = notification.flags | Notification.FLAG_ONGOING_EVENT | Notification.FLAG_NO_CLEAR | Notification.FLAG_FOREGROUND_SERVICE | Notification.FLAG_HIGH_PRIORITY | Notification.FLAG_AUTO_CANCEL;
            startForeground(notification_id, notification);
        }
    
        // Android8.0以后展示Notification需要创建渠道
        private void createNotificationChannel() {
            if (Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
                // 如果设置成 NotificationManager.IMPORTANCE_HIGH  或者 NotificationManager.IMPORTANCE_DEFAULT 的话会出现提示音,而且无法取消
                NotificationChannel channel = new NotificationChannel(notificationChannelId, notificationChannelName, NotificationManager.IMPORTANCE_LOW);
                getNotificationManager().createNotificationChannel(channel);
            }
        }
    
        // Notification管理器
        private NotificationManager getNotificationManager() {
            if (manager == null) {
                manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
            }
            return manager;
        }
    
        // Android8.0以后的版本使用此方法启动Notification
        private void showHighNotification() {
            if (Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
                Notification notification = new Notification.Builder(context, notificationChannelId)
                        .setContentTitle("买卖客户端")
                        .setContentText("正在运行中...")
                        /**点击事件监听器**/
                        .setContentIntent(PendingIntent.getBroadcast(context, 0, new Intent(ConstantValues.FOREGROUND_NOTIFICATION_CLICKED), 0))
                        /**消失的监听器**/
                        .setDeleteIntent(PendingIntent.getBroadcast(context, 0, new Intent(ConstantValues.FOREGROUND_NOTIFICATION_DISMISS), 0))
                        .setLargeIcon(BitmapFactory.decodeResource(context.getResources(), R.mipmap.ic_launcher))
                        .setSmallIcon(R.mipmap.ic_launcher) //设置小图标,4.x在右边,5.x在左边
                        /**通知产生的时间,会在通知信息里显示**/
                        .setWhen(System.currentTimeMillis())
                        .setShowWhen(true)
                        /**设置该通知优先级**/
                        .setPriority(Notification.PRIORITY_MAX)
                        /**设置这个标志当用户单击面板就可以让通知将自动取消**/
                        .setAutoCancel(false)
                        /**设置他为一个正在进行的通知。他们通常是用来表示一个后台任务,用户积极参与(如播放音乐)或以某种方式正在等待,因此占用设备(如一个文件下载,同步操作,主动网络连接)**/
                        .setOngoing(true)
                        /**向通知添加声音、闪灯和振动效果的最简单、最一致的方式是使用当前的用户默认设置,使用defaults属性,可以组合:**/
                        /**.setDefaults(Notification.DEFAULT_VIBRATE or Notification.DEFAULT_SOUND)**/
                        .build();
                notification.flags = notification.flags | Notification.FLAG_ONGOING_EVENT | Notification.FLAG_NO_CLEAR | Notification.FLAG_FOREGROUND_SERVICE | Notification.FLAG_HIGH_PRIORITY | Notification.FLAG_AUTO_CANCEL;
                startForeground(notification_id , notification);
            }
        }
    
        // 隐藏Notification
        public void hideNotification() {
            // 删除通道
            if (Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
                if (getNotificationManager().getNotificationChannel(notificationChannelId) != null) {
                    getNotificationManager().cancel(notification_id);
                    getNotificationManager().deleteNotificationChannel(notificationChannelId);
                }
            }
        }
    
        @Override
        public void onDestroy() {
            super.onDestroy();
            // 停止前台服务--参数:表示是否移除之前的通知
            stopForeground(true);
        }
    }
    

    在Application里面对Service进行绑定,然后在绝大部分页面(最好是BaseActivity)的OnResume方法里面调用Application里面的方法校验Service是否存活,这样就基本上保证Service不会被杀掉了

    import android.app.Application;
    import android.content.ComponentName;
    import android.content.Context;
    import android.content.Intent;
    import android.content.ServiceConnection;
    import android.os.Build;
    import android.os.IBinder;
    
    public class App extends Application {
        private static Context context;
        private static BuySellServiceConnection serviceConnection;
        private static BuySellService serviceController;
    
        @Override
        public void onCreate() {
            super.onCreate();
            context = App.this;
        }
    
        public static Context getContext() {
            return context;
        }
    
        // 隐藏服务的Notification
        public static void hideServiceNotification() {
            if (serviceController != null) {
                serviceController.hideNotification();
            }
        }
    
        // 校验Service的存活状态
        public static void checkService() {
            if (context != null) {
                // 判定服务是否仍然在后台运行
                boolean serviceRunning = ServiceUtil.isServiceRunning(BuySellService.class.getName(), context);
                if (!serviceRunning) {
                    Intent buySellIntent = new Intent(context.getApplicationContext(), BuySellService.class);
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                        context.startForegroundService(buySellIntent );
                    } else {
                        context.startService(buySellIntent );
                    }
                    if (serviceConnection == null) {
                        serviceConnection = new BuySellServiceConnection();
                    }
                    // 绑定当前服务
                    context.bindService(new Intent(context, BuySellService.class), serviceConnection, Context.BIND_IMPORTANT);
                }
            }
        }
    
        /**
         * 绑定连接需要ServiceConnection
         */
        static class BuySellServiceConnection implements ServiceConnection {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                // 这里可以通过IBinder获取到在Service的onBind方法里面传递过来的Binder对象
                // serviceController = ProcessConnection.Stub.asInterface(service);
                if (service instanceof BuySellService.BuySellBinder) {
                    serviceController = ((BuySellService.BuySellBinder) service).getService();
                }
            }
    
            @Override
            public void onServiceDisconnected(ComponentName name) {
                // 服务被干掉;连接断掉的时候走此回调
                checkService();
            }
        }
    }
    

    最后,在登录完毕之后,执行App.checkService(),然后在LoginActivity的OnDestory方法里面执行App.hideServiceNotification() 就行了,下次打开,可以在SplashActivity的OnCreate中校验当前是否登录成功,成功的话SplashActivity的OnCreate中执行App.checkService(),在SplashActivity的OnDestory方法里面执行App.hideServiceNotification() 就行了;如果要做保活的话,可以在BaseActivity的OnResume里面执行App.checkService(),在BaseActivity的OnDestory方法里面执行App.hideServiceNotification()

    相关文章

      网友评论

        本文标题:Service隐藏Notification和简单保活操作

        本文链接:https://www.haomeiwen.com/subject/ukghictx.html