/**
* 安卓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); } }
问题描述:
- 我现在有一个简单的Demo,一个三个Activity,BaseActivity,LoginActivity,MainActivity.
- 分别让LoginActivity,MainActivity继承BaseActivity,在MainActivity中使用startService()启动FirstService,在FirstService的onDestroy()方法中发送通知,通知当前APP的使用者,进程被销毁,APP已退出,可是不知道Service什么时候被GM回收,为了测试通知我就在MainActivity的onCreate()方法中直接发送通知.测试通知的兼容性
- 在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的源码,有需要的朋友可以直接复制使用
- 首先自定义一个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. 布局文件效果图: