Android 通知(Notification)兼容到Android Q,以及使用中的bug

/**
     * 安卓8.0以後創建通知需要做兼容
     * channelId 要唯一,自定義即可,如 "進程銷燬通知","TestNotification","FirstServiceNotification",自定義即可
     * 創建包含內容的通知,點擊通知跳轉LoginActivity
     * 第一個參數是Context 的時候不能置爲前臺進程,只能發送通知等操作
     */
    public static void createHasDataNotification(Context context, String channelId, int notificationId) {
        //創建通知管理器
        NotificationManager manager = (NotificationManager) context.getSystemService(context.NOTIFICATION_SERVICE);
        //設置點擊通知時的響應事件
        Intent intent = new Intent(context, LoginActivity.class);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
            //NotificationManager.IMPORTANCE_MIN: 靜默;
            //NotificationManager.IMPORTANCE_HIGH:隨系統使用聲音或振動
            NotificationChannel channel = new NotificationChannel(channelId, channelId, NotificationManager.IMPORTANCE_HIGH);
            channel.enableLights(true);
            channel.setLightColor(Color.RED);
            channel.setShowBadge(true);
            channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
            Notification notification = new Notification.Builder(context)
                    .setTicker("緊急通知")
                    .setContentText("聚合環境切換APP已退出,請點擊重新啓動")//設置通知內容
                    .setAutoCancel(true)//設置點擊通知後自動刪除通知
                    .setChannelId(channelId) //設置Id,安卓8.0後必須加
                    .setContentIntent(pendingIntent) //設置點擊通知時的響應事件
                    .setSmallIcon(R.mipmap.changyoulogo)//通知左側的小圖標
                    .build();
            //設置當前進程爲前臺進程,第一個參數是Context不能置爲前臺進程
//            context.startForeground(notificationId, notification);
            manager.createNotificationChannel(channel);
            manager.notify(66, notification);
        } else {
            Notification notification = new Notification.Builder(context)
                    .setTicker("緊急通知")
                    .setContentText("聚合環境切換APP已退出,請點擊重新啓動")//設置通知內容
                    .setAutoCancel(true)//設置點擊通知後自動刪除通知
                    .setContentIntent(pendingIntent) //設置點擊通知時的響應事件
                    .setSmallIcon(R.mipmap.changyoulogo)//通知左側的小圖標
                    .setDefaults(Notification.DEFAULT_SOUND)//使用系統默認的聲音或震動
                    .build();
            //設置當前進程爲前臺進程,第一個參數是Context不能置爲前臺進程
//            context.startForeground(notificationId, notification);
            if (null != notification) {
                notification.flags |= Notification.FLAG_AUTO_CANCEL;
            }
            //創建通知管理器
            manager.notify(66, notification);
        }
    }
/**
 * 安卓8.0以後創建通知要做兼容處理
 * channelId 要唯一,自定義即可,如 "進程銷燬通知","TestNotification","FirstServiceNotification",自定義即可
 * 創建包含內容的通知,點擊通知跳轉LoginActivity
 * 第一個參數是Service 就可以置爲前臺進程,當前通知從Service中發出
 */
public static void createHasDataNotification(Service context, String channelId, int
        notificationId) {
    //創建通知管理器
    NotificationManager manager = (NotificationManager) context.getSystemService(context.NOTIFICATION_SERVICE);
    //設置點擊通知時的響應事件
    Intent intent = new Intent(context, LoginActivity.class);
    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
        //NotificationManager.IMPORTANCE_MIN: 靜默;
        //NotificationManager.IMPORTANCE_HIGH:隨系統使用聲音或振動
        NotificationChannel channel = new NotificationChannel(channelId, channelId, NotificationManager.IMPORTANCE_HIGH);
        channel.enableLights(true);
        channel.setLightColor(Color.RED);
        channel.setShowBadge(true);
        channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
        Notification notification = new Notification.Builder(context)
                .setTicker("緊急通知")
                .setContentText("PP已退出,請點擊重新啓動")//設置通知內容
                .setAutoCancel(true)//設置點擊通知後自動刪除通知
                .setChannelId(channelId) //設置Id,安卓8.0後必須加
                .setContentIntent(pendingIntent) //設置點擊通知時的響應事件
                .setSmallIcon(R.mipmap.changyoulogo)//通知左側的小圖標
                .build();
        //設置當前進程爲前臺進程,增加進程保活率
        context.startForeground(notificationId, notification);
        manager.createNotificationChannel(channel);
        manager.notify(66, notification);
    } else {
        Notification notification = new Notification.Builder(context)
                .setTicker("緊急通知")
                .setContentText("APP已退出,請點擊重新啓動")//設置通知內容
                .setAutoCancel(true)//設置點擊通知後自動刪除通知
                .setContentIntent(pendingIntent) //設置點擊通知時的響應事件
                .setSmallIcon(R.mipmap.changyoulogo)//通知左側的小圖標
                .setDefaults(Notification.DEFAULT_SOUND)//使用系統默認的聲音或震動
                .build();
        //設置當前進程爲前臺進程,增加進程保活率
        context.startForeground(notificationId, notification);
        if (null != notification) {
            notification.flags |= Notification.FLAG_AUTO_CANCEL;
        }
        //創建通知管理器
        manager.notify(66, notification);
    }
}

問題描述:

  1. 我現在有一個簡單的Demo,一個三個Activity,BaseActivity,LoginActivity,MainActivity.
  2. 分別讓LoginActivity,MainActivity繼承BaseActivity,在MainActivity中使用startService()啓動FirstService,在FirstService的onDestroy()方法中發送通知,通知當前APP的使用者,進程被銷燬,APP已退出,可是不知道Service什麼時候被GM回收,爲了測試通知我就在MainActivity的onCreate()方法中直接發送通知.測試通知的兼容性
  3. 在BaseActivity中重寫onBackPressed(),監聽返回按鈕,彈出Dialog,讓用戶選擇是否退出,如果退出則還原一些設置,並執行退出邏輯,代碼如下:

4. 正式步入主題:LoginActivity登錄成功後跳轉MainActivity,MainActivity的onCreate方法中發送通知:

   4.1 現在登錄成功,通知也發送出去了,頁面停留在MainActivity,此時按下home鍵,回到桌面,點擊通知會跳轉到LoginActivity頁面, 執行登錄,成功後跳轉到MainActivity頁面,此時按下返回鍵,退出App,成功退出APP以後,APP會再次啓動,如果登錄成功後停留在MainActivity頁面,不點擊home鍵,現在APP在前臺顯示,點擊通知,執行上面的退出邏輯,則APP不會重新啓動一次.

  4.2問題分析:第一個APP啓動後,點擊home到後臺後,進程並沒有被銷燬,這個LoginActivity和MainActivity還存在棧中,點擊通知跳轉到LoginActivity登錄成功跳轉到MainActivity,又重新開啓一個線程,又會創建一個LoginActivity和MainActivity,存放在棧中,此時退出的是第二個棧的LoginActivity和MainActivity,第一次創建的LoginActivity和MainActivity並沒有被殺死,還存放在棧中,所以會重新啓動一次.

5.解決辦法:

直接給BaseActivity,MainActivity,LoginActivity設置singleInstance的啓動模式,讓每個Activity單獨使用一個棧,當點擊通知再次啓動的時候,棧中有當前Activity對象,就不會重新創建一次,故此在棧中就一個MainActivity,LoginActivity的對象,退出的時候就可以直接退出,不會出現重啓的現象

下面是自定義Dialog的代碼,也就是上面的退出dialog的源碼,有需要的朋友可以直接複製使用

  1. 首先自定義一個Dialog
/**
 * 用自定義dialog
 */

public class CustomDialog extends Dialog {
    private Button commitButton;//確定按鈕
    private Button cancelButton;//取消按鈕
    private TextView titleTextView;//標題
    private TextView messageTextView;//提示文字
    private String titleText;//設置給標題的文字
    private String messageText;//提醒內容
    private String commitText;//設置給確定按鈕的文字
    private String cancelText;//設置給取消按鈕的文字
    private ColorStateList titleTextColor;//設置給標題文字的顏色
    private ColorStateList messageTextColor;//設置給提醒內容的文字顏色
    private onCommitClickListener commitClickListener;//確定按鈕的監聽接口
    private onCancelClickListener cancelClickListener;//取消按鈕的監聽接口

    public CustomDialog(@NonNull Context context) {
        super(context, R.style.CustomDialogStyle);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.custom_dialog_layout);
        this.setCanceledOnTouchOutside(false);
        //初始化控件
        initView();
        //初始化dialog的內容
        initDate();
        //按鈕點擊監聽
        clickListener();
    }

    private void clickListener() {
        commitButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (commitClickListener != null)
                    commitClickListener.onYesClick();
            }
        });
        cancelButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (cancelClickListener != null)
                    cancelClickListener.onNoClick();
            }
        });
    }

    private void initView() {
        titleTextView = (TextView) findViewById(R.id.custom_dialog_title_textview);
        messageTextView = (TextView) findViewById(R.id.custom_dialog_message_textview);
        commitButton = (Button) findViewById(R.id.custom_dialog_commit_button);
        cancelButton = (Button) findViewById(R.id.custom_dialog_cancel_button);
    }

    //設置文字和顏色
    private void initDate() {
        if (!TextUtils.isEmpty(titleText)) {//標題文字
            titleTextView.setText(titleText);
        }
        if (!TextUtils.isEmpty(messageText)) {//提示內容
            messageTextView.setText(messageText);
        }
        if (!TextUtils.isEmpty(commitText)) {//確定按鈕文字
            commitButton.setText(commitText);
        }
        if (!TextUtils.isEmpty(cancelText)) {//取消按鈕文字
            cancelButton.setText(cancelText);
        }
        if (titleTextColor != null) {//標題文字顏色
            titleTextView.setTextColor(titleTextColor);
        }
        if (messageTextColor != null) {//提醒文字顏色
            messageTextView.setTextColor(messageTextColor);
        }
    }

    public void setTitle(String title) {
        this.titleText = title;
    }

    public void setTitleColor(int color) {
        titleTextColor = ColorStateList.valueOf(color);
    }

    public void setMessage(String message) {
        this.messageText = message;
    }

    public void setMessageColor(int color) {
        messageTextColor = ColorStateList.valueOf(color);
    }

    public void setOnCommitClickListener(String btnText, onCommitClickListener yesClickListener) {
        commitText = btnText;
        this.commitClickListener = yesClickListener;
    }

    public void setOnCancelClickListener(String btnText, onCancelClickListener noClickListener) {
        cancelText = btnText;
        this.cancelClickListener = noClickListener;
    }

    //確定按鈕回調接口
    public interface onCommitClickListener {
        void onYesClick();
    }

    //取消按鈕的回調接口
    public interface onCancelClickListener {
        void onNoClick();
    }
}

 2. 在res/values/styles.xml 創建下面的自定義的dialogStyle

<style name="CustomDialogStyle" parent="@android:style/Theme.Dialog">
        <item name="android:windowFrame">@null</item>
        <item name="android:windowIsFloating">true</item>
        <item name="android:windowIsTranslucent">true</item>
        <item name="android:windowNoTitle">true</item>
        <item name="android:background">@android:color/transparent</item>
        <item name="android:windowBackground">@android:color/transparent</item>
        <item name="android:backgroundDimEnabled">true</item>
        <item name="android:backgroundDimAmount">0.8</item><!--背景透明度-->
    </style>

  3. 創建layou佈局文件 

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_margin="15dp"
    android:background="@drawable/backgroud_style"
    android:orientation="vertical">

    <TextView
        android:id="@+id/custom_dialog_title_textview"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="25dp"
        android:gravity="center"
        android:text="提 示"
        android:textColor="#ff0000"
        android:textSize="22sp" />

    <TextView
        android:id="@+id/custom_dialog_message_textview"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginBottom="30dp"
        android:layout_marginLeft="10dp"
        android:layout_marginRight="10dp"
        android:layout_marginTop="20dp"
        android:lineSpacingExtra="3dp"
        android:text="@string/dialog_exit_hint"
        android:textColor="#000000"
        android:textSize="18sp" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:orientation="horizontal">

        <Button
            android:id="@+id/custom_dialog_commit_button"
            android:layout_width="match_parent"
            android:layout_height="40dp"
            android:layout_marginRight="0.75dp"
            android:layout_weight="1"
            android:background="@drawable/button_commit"
            android:text="確 定"
            android:textColor="#ffffff"
            android:textSize="18sp" />

        <Button
            android:id="@+id/custom_dialog_cancel_button"
            android:layout_width="match_parent"
            android:layout_height="40dp"
            android:layout_marginLeft="0.75dp"
            android:layout_weight="1"
            android:background="@drawable/button_cancel"
            android:text="取 消"
            android:textColor="#ffffff"
            android:textSize="18sp" />
    </LinearLayout>

</LinearLayout>

4. 佈局文件效果圖:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章