如果你的APP有多种弹窗,试想一下,你的APP中有(活动弹窗、登录弹窗、更新弹窗、alert弹窗...)它们出现的时机有可能会重叠,那么弹窗的优先级就有必要做了,活动如:
1.创建一个单例manger用来维护弹窗优先级
public static DialogManger getInstance(Context context) {
if (mInstance == null) {
synchronized (DialogManger.class) {
if (mInstance == null) {
mInstance = new DialogManger(context.getApplicationContext());
}
}
}
return mInstance;
}
2.在manger中用常量定义各种弹框的级别
/**
* 活动弹窗的优先级
*/
public final static int AD_PRIORITY = 1;
/**
* 更新弹窗的优先级
*/
public final static int UPDATE_PRIORITY = 2;
/**
* alert弹窗的优先级
*/
public final static int ALERT_PRIORITY = 3;
/**
* 登录弹窗的优先级
*/
public final static int LOGIN_PRIORITY = 4;
/**
* other弹窗的优先级
*/
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.创建一个stack来存储每种弹框Tag
我们先创建一个DialogTag类,序列化,重写equals方法,用于标记每种弹框
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中创建stack存储DialogTag
private Stack mDialogLevels = new Stack<>();
4.提供一个方法根据优先级处理弹框是否可显示
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;
}
}
每个弹框打开前会调用次方法,如果stack的size为0时,说明还没有任何弹窗打开,这时候第一个弹窗就push到栈顶,
如果已经有开启的弹窗,下一个弹窗进来,首先就会取栈顶的弹窗Tag与本次要启动弹窗的Tag级别做比较,
如果进来的弹窗优先级比栈顶的优先级高,那么这个弹窗就可以开启,并且push到栈顶,否则就不能开启
因为stack是先进后出特点,所以每个Tag进来都会在栈顶,由于每次新进来的弹框都会取栈顶的与之比较,所以栈顶优先级肯定高于站内其他Tag
5.弹框销毁时通知manger中stack移除Tag
我们弹框打开时会把Tag push到stack里,当弹框销毁时也要从stack中移除,我们可以通过广播通知manger调用dismiss来移除Tag
在构造方法中注册广播
private DialogManger(Context context) {
IntentFilter filter = new IntentFilter(ACTION_DIALOG_DISMISS);
LocalBroadcastManager.getInstance(context).registerReceiver(mDialogDismissReceiver, filter);
}
在收到广播后,调用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);
}
}
弹窗启动前创建一个DialogTag,调用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);
}
}
在弹框销毁时,发送广播通知manger
@Override
protected void onDestroy() {
super.onDestroy();
LocalBroadcastManager.getInstance(this)
.sendBroadcast(new Intent(DialogManger.ACTION_DIALOG_DISMISS)
.putExtra(DialogManger.DIALOG_TAG, mDialogTag));
}
因为项目需求 我这里的弹框都是用Activity使用Dialog样式
接下来我们测试一下
我这创建了几种Dialog样式的Activity,作为Dialog
在一个button的click方法中,每点击一次会随机生成1-5之间的5个数字代表5个DialogActivity的优先级,每次生成的5个数字都用TextView显示在MainActivity上,
方便观察,
public void onClick(View view) {
count = randomCommon(0, 6, 5);//随机生成1-5之间的5个数字
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();
}
创建一个倒计时,每间隔1秒启动一个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();
}
根据优先级数组中的数字级别来启动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;
}
}
看下效果:
我们看到优先级数组显示为 3、5、1、4、2,那么优先级为3、5的弹框依次弹出,后面的1、4、2,优先级都低于5,没有弹出。
再看一次
这次只有优先级为1的没有弹出
好啦,代码比较简单,相信一看就能明白,demo我已传到GitHub,欢迎star,谢谢!
https://github.com/xiaviv/DialogLevels