Service隱藏Notification和簡單?;畈僮?/h2>

其實在前面我寫的《Notification相關(guān)操作》文章里面提了一嘴這個事情,Android 8.0以后啟動Service需要采用context.startForegroundService(intent)的形式啟動,而這個操作會導(dǎo)致一個Service必須啟動一個Notification的問題,如果被要求隱藏這個Notification的話就需要采取一些特殊手段了:

判定Service是否正在后臺運(yùn)行的工具類:

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;                          // 狀態(tài)欄 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) {
            // 創(chuàng)建渠道
            createNotificationChannel();
            // 展示通知
            showHighNotification();
        }/** else {
            // 展示通知
            showSimpleNotification();
        }**/
    }

    // Android8.0以前的版本使用此方法啟動Notification
    private void showSimpleNotification() {
        Notification notification = new NotificationCompat.Builder(context, notificationChannelId)
                .setContentTitle("買賣客戶端")
                .setContentText("正在運(yùn)行中...")
                /**點(diǎn)擊事件監(jiān)聽器**/
                .setContentIntent(PendingIntent.getBroadcast(context, 0, new Intent(ConstantValues.FOREGROUND_NOTIFICATION_CLICKED), 0))
                /**消失的監(jiān)聽器**/
                .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) //設(shè)置小圖標(biāo),4.x在右邊,5.x在左邊
                /**通知產(chǎn)生的時間,會在通知信息里顯示**/
                .setWhen(System.currentTimeMillis())
                /**設(shè)置該通知優(yōu)先級**/
                .setPriority(Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.JELLY_BEAN ? NotificationCompat.PRIORITY_MAX : Notification.PRIORITY_MAX)
                /**設(shè)置這個標(biāo)志當(dāng)用戶單擊面板就可以讓通知將自動取消**/
                .setAutoCancel(false)
                /**設(shè)置他為一個正在進(jìn)行的通知。他們通常是用來表示一個后臺任務(wù),用戶積極參與(如播放音樂)或以某種方式正在等待,因此占用設(shè)備(如一個文件下載,同步操作,主動網(wǎng)絡(luò)連接)**/
                .setOngoing(true)
                /**向通知添加聲音、閃燈和振動效果的最簡單、最一致的方式是使用當(dāng)前的用戶默認(rèn)設(shè)置,使用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需要創(chuàng)建渠道
    private void createNotificationChannel() {
        if (Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
            // 如果設(shè)置成 NotificationManager.IMPORTANCE_HIGH  或者 NotificationManager.IMPORTANCE_DEFAULT 的話會出現(xiàn)提示音,而且無法取消
            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("正在運(yùn)行中...")
                    /**點(diǎn)擊事件監(jiān)聽器**/
                    .setContentIntent(PendingIntent.getBroadcast(context, 0, new Intent(ConstantValues.FOREGROUND_NOTIFICATION_CLICKED), 0))
                    /**消失的監(jiān)聽器**/
                    .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) //設(shè)置小圖標(biāo),4.x在右邊,5.x在左邊
                    /**通知產(chǎn)生的時間,會在通知信息里顯示**/
                    .setWhen(System.currentTimeMillis())
                    .setShowWhen(true)
                    /**設(shè)置該通知優(yōu)先級**/
                    .setPriority(Notification.PRIORITY_MAX)
                    /**設(shè)置這個標(biāo)志當(dāng)用戶單擊面板就可以讓通知將自動取消**/
                    .setAutoCancel(false)
                    /**設(shè)置他為一個正在進(jìn)行的通知。他們通常是用來表示一個后臺任務(wù),用戶積極參與(如播放音樂)或以某種方式正在等待,因此占用設(shè)備(如一個文件下載,同步操作,主動網(wǎng)絡(luò)連接)**/
                    .setOngoing(true)
                    /**向通知添加聲音、閃燈和振動效果的最簡單、最一致的方式是使用當(dāng)前的用戶默認(rèn)設(shè)置,使用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();
        // 停止前臺服務(wù)--參數(shù):表示是否移除之前的通知
        stopForeground(true);
    }
}

在Application里面對Service進(jìn)行綁定,然后在絕大部分頁面(最好是BaseActivity)的OnResume方法里面調(diào)用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;
    }

    // 隱藏服務(wù)的Notification
    public static void hideServiceNotification() {
        if (serviceController != null) {
            serviceController.hideNotification();
        }
    }

    // 校驗Service的存活狀態(tài)
    public static void checkService() {
        if (context != null) {
            // 判定服務(wù)是否仍然在后臺運(yùn)行
            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();
                }
                // 綁定當(dāng)前服務(wù)
                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方法里面?zhèn)鬟f過來的Binder對象
            // serviceController = ProcessConnection.Stub.asInterface(service);
            if (service instanceof BuySellService.BuySellBinder) {
                serviceController = ((BuySellService.BuySellBinder) service).getService();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            // 服務(wù)被干掉;連接斷掉的時候走此回調(diào)
            checkService();
        }
    }
}

最后,在登錄完畢之后,執(zhí)行App.checkService(),然后在LoginActivity的OnDestory方法里面執(zhí)行App.hideServiceNotification() 就行了,下次打開,可以在SplashActivity的OnCreate中校驗當(dāng)前是否登錄成功,成功的話SplashActivity的OnCreate中執(zhí)行App.checkService(),在SplashActivity的OnDestory方法里面執(zhí)行App.hideServiceNotification() 就行了;如果要做?;畹脑挘梢栽贐aseActivity的OnResume里面執(zhí)行App.checkService(),在BaseActivity的OnDestory方法里面執(zhí)行App.hideServiceNotification()

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容