如果你的APP有多種彈窗,試想一下,你的APP中有(活動(dòng)彈窗、登錄彈窗、更新彈窗、alert彈窗...)它們出現(xiàn)的時(shí)機(jī)有可能會(huì)重疊,那么彈窗的優(yōu)先級(jí)就有必要做了,活動(dòng)如:

WechatIMG1799.jpeg
1.創(chuàng)建一個(gè)單例manger用來維護(hù)彈窗優(yōu)先級(jí)
public static DialogManger getInstance(Context context) {
if (mInstance == null) {
synchronized (DialogManger.class) {
if (mInstance == null) {
mInstance = new DialogManger(context.getApplicationContext());
}
}
}
return mInstance;
}
2.在manger中用常量定義各種彈框的級(jí)別
/**
* 活動(dòng)彈窗的優(yōu)先級(jí)
*/
public final static int AD_PRIORITY = 1;
/**
* 更新彈窗的優(yōu)先級(jí)
*/
public final static int UPDATE_PRIORITY = 2;
/**
* alert彈窗的優(yōu)先級(jí)
*/
public final static int ALERT_PRIORITY = 3;
/**
* 登錄彈窗的優(yōu)先級(jí)
*/
public final static int LOGIN_PRIORITY = 4;
/**
* other彈窗的優(yōu)先級(jí)
*/
public final static int OTHER_PRIORITY = 5;
@RestrictTo(GROUP_ID)
@IntDef({AD_PRIORITY, UPDATE_PRIORITY, ALERT_PRIORITY, LOGIN_PRIORITY, OTHER_PRIORITY})
@Retention(RetentionPolicy.SOURCE)
public @interface DialogLevel {
}
3.創(chuàng)建一個(gè)stack來存儲(chǔ)每種彈框Tag
我們先創(chuàng)建一個(gè)DialogTag類,序列化,重寫equals方法,用于標(biāo)記每種彈框
public class DialogTag implements Serializable {
int level;
String uuid;
public DialogTag(@DialogManger.DialogLevel int level, String uuid) {
this.level = level;
this.uuid = uuid;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof DialogTag) {
DialogTag anotherDialogTag = (DialogTag) obj;
if (this.level == anotherDialogTag.level
&& this.uuid.equals(anotherDialogTag.uuid)) {
return true;
}
}
return false;
}
}
在manger中創(chuàng)建stack存儲(chǔ)DialogTag
private Stack<DialogTag> mDialogLevels = new Stack<>();
4.提供一個(gè)方法根據(jù)優(yōu)先級(jí)處理彈框是否可顯示
public boolean canShow(DialogTag tag) {
if (mDialogLevels.size() > 0) {
DialogTag topTag = mDialogLevels.peek();
if (tag.level >= topTag.level) {
mDialogLevels.push(tag);
return true;
} else {
return false;
}
} else {
mDialogLevels.push(tag);
return true;
}
}
每個(gè)彈框打開前會(huì)調(diào)用次方法,如果stack的size為0時(shí),說明還沒有任何彈窗打開,這時(shí)候第一個(gè)彈窗就push到棧頂,
如果已經(jīng)有開啟的彈窗,下一個(gè)彈窗進(jìn)來,首先就會(huì)取棧頂?shù)膹棿癟ag與本次要啟動(dòng)彈窗的Tag級(jí)別做比較,
如果進(jìn)來的彈窗優(yōu)先級(jí)比棧頂?shù)膬?yōu)先級(jí)高,那么這個(gè)彈窗就可以開啟,并且push到棧頂,否則就不能開啟
因?yàn)閟tack是先進(jìn)后出特點(diǎn),所以每個(gè)Tag進(jìn)來都會(huì)在棧頂,由于每次新進(jìn)來的彈框都會(huì)取棧頂?shù)呐c之比較,所以棧頂優(yōu)先級(jí)肯定高于站內(nèi)其他Tag
5.彈框銷毀時(shí)通知manger中stack移除Tag
我們彈框打開時(shí)會(huì)把Tag push到stack里,當(dāng)彈框銷毀時(shí)也要從stack中移除,我們可以通過廣播通知manger調(diào)用dismiss來移除Tag
在構(gòu)造方法中注冊(cè)廣播
private DialogManger(Context context) {
IntentFilter filter = new IntentFilter(ACTION_DIALOG_DISMISS);
LocalBroadcastManager.getInstance(context).registerReceiver(mDialogDismissReceiver, filter);
}
在收到廣播后,調(diào)用dismiss()
public class DialogDismissReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (intent != null) {
DialogTag tag = (DialogTag) intent.getSerializableExtra(DIALOG_TAG);
dismiss(tag);
}
}
}
private void dismiss(DialogTag tag) {
int i = mDialogLevels.lastIndexOf(tag);
if (i >= 0) {
mDialogLevels.removeElementAt(i);
}
}
彈窗啟動(dòng)前創(chuàng)建一個(gè)DialogTag,調(diào)用manger的canShow()
public static void launch(Activity activity) {
DialogTag dialogTag = new DialogTag(DialogManger.ALERT_PRIORITY, UUID.randomUUID().toString());
if (DialogManger.getInstance(activity).canShow(dialogTag)) {
Intent intent = new Intent(activity, AlertDialogActivity.class);
intent.putExtra(DialogManger.DIALOG_TAG, dialogTag);
activity.startActivity(intent);
}
}
在彈框銷毀時(shí),發(fā)送廣播通知manger
@Override
protected void onDestroy() {
super.onDestroy();
LocalBroadcastManager.getInstance(this)
.sendBroadcast(new Intent(DialogManger.ACTION_DIALOG_DISMISS)
.putExtra(DialogManger.DIALOG_TAG, mDialogTag));
}
因?yàn)轫?xiàng)目需求 我這里的彈框都是用Activity使用Dialog樣式
接下來我們測(cè)試一下

Dialog樣式的Activity.png
我這創(chuàng)建了幾種Dialog樣式的Activity,作為Dialog
在一個(gè)button的click方法中,每點(diǎn)擊一次會(huì)隨機(jī)生成1-5之間的5個(gè)數(shù)字代表5個(gè)DialogActivity的優(yōu)先級(jí),每次生成的5個(gè)數(shù)字都用TextView顯示在MainActivity上,
方便觀察,
public void onClick(View view) {
count = randomCommon(0, 6, 5);//隨機(jī)生成1-5之間的5個(gè)數(shù)字
assert count != null;
for (int level : count) {
sb.append(level);
if (level != count[count.length - 1]) {
sb.append(",");
}
}
tv_level.setText(String.valueOf("startDialogActivity level : " + sb.toString()));
sb.setLength(0);
startCountdown();
}
創(chuàng)建一個(gè)倒計(jì)時(shí),每間隔1秒啟動(dòng)一個(gè)DialogActivity
private synchronized void startCountdown() {
mCountDownTimer = new CountDownTimer(7 * 1000, 1000) {
@Override
public void onTick(long millisUntilFinished) {
if (index < count.length) {
startDialogActivity(count[index]);
index++;
} else {
index = 0;
endCountdown();
}
Log.e(TAG, "onTick: index :" + index);
}
@Override
public void onFinish() {
}
}.start();
}
根據(jù)優(yōu)先級(jí)數(shù)組中的數(shù)字級(jí)別來啟動(dòng)DialogActivity
private void startDialogActivity(int levels) {
switch (levels) {
case DialogManger.AD_PRIORITY:
ADDialogActivity.launch(MainActivity.this);
break;
case DialogManger.UPDATE_PRIORITY:
UpdateDialogActivity.launch(MainActivity.this);
break;
case DialogManger.ALERT_PRIORITY:
AlertDialogActivity.launch(MainActivity.this);
break;
case DialogManger.LOGIN_PRIORITY:
LoginDialogActivity.launch(MainActivity.this);
break;
case DialogManger.OTHER_PRIORITY:
OtherDialogActivity.launch(MainActivity.this);
break;
}
}
看下效果:

test.gif
我們看到優(yōu)先級(jí)數(shù)組顯示為 3、5、1、4、2,那么優(yōu)先級(jí)為3、5的彈框依次彈出,后面的1、4、2,優(yōu)先級(jí)都低于5,沒有彈出。
再看一次

test2.gif
這次只有優(yōu)先級(jí)為1的沒有彈出
好啦,代碼比較簡(jiǎn)單,相信一看就能明白,demo我已傳到GitHub,歡迎star,謝謝!
https://github.com/xiaviv/DialogLevels