/**
* 安卓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. 佈局文件效果圖: