开发中Dialog弹窗优先级控制

如果你的APP有多种弹窗,试想一下,你的APP中有(活动弹窗、登录弹窗、更新弹窗、alert弹窗...)它们出现的时机有可能会重叠,那么弹窗的优先级就有必要做了,活动如:


WechatIMG1799.jpeg

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<DialogTag> 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.png

我这创建了几种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;
    }

}

看下效果:

test.gif

我们看到优先级数组显示为 3、5、1、4、2,那么优先级为3、5的弹框依次弹出,后面的1、4、2,优先级都低于5,没有弹出。
再看一次

test2.gif

这次只有优先级为1的没有弹出

好啦,代码比较简单,相信一看就能明白,demo我已传到GitHub,欢迎star,谢谢!
https://github.com/xiaviv/DialogLevels

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,980评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,178评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,868评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,498评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,492评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,521评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,910评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,569评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,793评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,559评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,639评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,342评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,931评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,904评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,144评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,833评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,350评论 2 342

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,378评论 25 707
  • ¥开启¥ 【iAPP实现进入界面执行逐一显】 〖2017-08-25 15:22:14〗 《//首先开一个线程,因...
    小菜c阅读 6,345评论 0 17
  • 哎呀呀 ,马上就要面临找工作了,媛媛心里紧张呀. 作为一个即将毕业的Android程序媛,开始面临找工作了,...
    仇诺伊阅读 4,526评论 7 59
  • 来自:【http://benbeng.leanote.com/post/On-Demand-Resources-G...
    LV大树阅读 1,446评论 0 2
  • 将秋风采集 酿在咸菜坛子里 压上时间的瓦砾 汗水裹着盐粒成防腐剂 等着春天里 和你 就着桃花尝秋风酿手艺 想趁着白...
    乔安的故事阅读 164评论 0 0