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. 布局文件效果图:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值