开发中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 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

你可能感兴趣的:(开发中Dialog弹窗优先级控制)