Generally, in the home page of a project, there are often multiple dialog boxes to pop up, such as activity pop-ups, update pop-ups, scoring pop-ups and so on, and these pop-ups have priority order. These pop-ups are generally displayed after the interface requests and returns the results. If only a few pop-ups are easy to deal with, the business logic can judge the order of display. If there are a dozen or more, it can be cumbersome and problematic to deal with.

Therefore, it is necessary to encapsulate a popover function that can be displayed in priority order. First of all, the functional requirements are as follows:

  • Blocking display of various pop-ups in priority order, starting with the highest priority by default
  • The next low – priority popover can be displayed only when the previous high – priority popover finishes or cancels
  • Specify a popover if there are no higher priority popovers to display
  • Before displaying a popover, you need to determine whether it can or needs to be displayed
  • Finds the specified popover based on priority, which is equivalent to a unique ID
  • Popovers include many types, Dialog, PopupWindow, Activity, and so on
  • Pop-ups that have been displayed can be displayed again according to the business logic
  • Pop-ups with the same priority are displayed in the order they are added

We then start coding to implement the functionality, starting with an enumeration class that lists the supported popover types, including Dialog, PopupWindow, Activity, and so on.

public enum WindowType {

    DIALOG,
    POUPOWINDOW,
    TOAST,
    SNACKBAR,
    WIDGET,
    ACTIVITY,
    OTHERS

}
Copy the code

Then define the popover interface IWindow, which defines the basic functions of the popover.

/** * public interface IWindow {/** * popup */ void show(Activity Activity); /** * popup close */ void dismiss(); /** * whether to display * @return */ Boolean isShowing(); / * * * Settings window to monitor * / void setOnWindowDismissListener (OnWindowDismissListener listener); /** * set window display listener */ void setOnWindowShowListener(OnWindowShowListener); }Copy the code

And listening interfaces that pop up and close,

/** * public interface OnWindowDismissListener {/** ** / void dismiss (); } /** * public interface OnWindowShowListener {void onShow(); }Copy the code

Next, define a wrapper class WindowWrapper to encapsulate popover related properties and states, including popover, priority, whether to display, form type, etc., which will be used when handling popover display logic.

Public class WindowWrapper {/** * window */ private IWindow mWindow; /** * Priority, the higher the priority */ private int mPriority; */ private Boolean isCanShow; /** * popover type */ private WindowType mWindowType; /** * private String mWindowName; private WindowWrapper(Builder builder) { mWindow = builder.window; mPriority = builder.priority; mWindowType = builder.windowType; isCanShow = builder.isCanShow; mWindowName = builder.windowName; } public IWindow getWindow() { return mWindow; } public void setWindow(IWindow window) { this.mWindow = window; } public int getPriority() { return mPriority; } public void setPriority(int priority) { this.mPriority = priority; } public WindowType getWindowType() { return mWindowType; } public void setWindowType(WindowType mWindowType) { this.mWindowType = mWindowType; } public boolean isCanShow() { return isCanShow; } public void setCanShow(boolean canShow) { isCanShow = canShow; } public String getWindowName() { return mWindowName; } public void setWindowName(String mWindowName) { this.mWindowName = mWindowName; } public class Builder {/** * window */ private IWindow window; /** * Priority, the higher the priority */ private int priority; /** * private WindowType WindowType; */ private Boolean isCanShow; /** * private String windowName; public Builder window(IWindow window) { this.window = window; return this; } public Builder priority(int priority) { this.priority = priority; return this; } public Builder windowType(WindowType type) { this.windowType = type; return this; } public Builder setCanShow(boolean canShow) { isCanShow = canShow; return this; } public String getWindowName() { return windowName; } public Builder setWindowName(String windowName) { this.windowName = windowName; return this; } public WindowWrapper build() { return new WindowWrapper(this); }}}Copy the code

Finally, through WindowTaskManager class to unify the organization and management of pop-ups add, display, close and other logic,

public class WindowTaskManager {
    private List<WindowWrapper> mWindows;


    private static WindowTaskManager mDefaultInstance;


    private WindowTaskManager() {
    }


    /**
     * 获取弹窗管理者
     */
    public static WindowTaskManager getInstance() {
        if (mDefaultInstance == null) {
            synchronized (WindowTaskManager.class) {
                if (mDefaultInstance == null) {
                    mDefaultInstance = new WindowTaskManager();
                }
            }
        }
        return mDefaultInstance;
    }


    /**
     * 添加弹窗
     *
     * @param windowWrapper 待显示的弹窗
     */
    public synchronized void addWindow(Activity activity, WindowWrapper windowWrapper) {
        if (windowWrapper != null) {
            if (mWindows == null) {
                mWindows = new ArrayList<>();
            }


            if (windowWrapper.getWindow() != null) {
                windowWrapper.getWindow().setOnWindowShowListener(new OnWindowShowListener() {
                    @Override
                    public void onShow() {
                        windowWrapper.setShowing(true);
                    }
                });


                windowWrapper.getWindow().setOnWindowDismissListener(new OnWindowDismissListener() {
                    @Override
                    public void onDismiss() {
                        windowWrapper.setShowing(false);
                        mWindows.remove(windowWrapper);
                        showNext(activity);
                    }
                });
            }


            mWindows.add(windowWrapper);
        }
    }


    /**
     * 弹窗满足展示条件
     *
     * @param priority
     */
    public synchronized void enableWindow(Activity activity, int priority, IWindow window) {
        WindowWrapper windowWrapper = getTargetWindow(priority);
        if (windowWrapper != null) {


            if (windowWrapper.getWindow() == null) {
                window.setOnWindowShowListener(new OnWindowShowListener() {
                    @Override
                    public void onShow() {
                        windowWrapper.setShowing(true);
                    }
                });


                window.setOnWindowDismissListener(new OnWindowDismissListener() {
                    @Override
                    public void onDismiss() {
                        windowWrapper.setShowing(false);
                        mWindows.remove(windowWrapper);
                        showNext(activity);
                    }
                });
            }


            windowWrapper.setCanShow(true);
            windowWrapper.setWindow(window);
            show(activity, priority);
        }
    }


    /**
     * 移除不需要显示弹窗
     *
     * @param priority
     */
    public synchronized void disableWindow(int priority) {
        WindowWrapper windowWrapper = getTargetWindow(priority);
        if (windowWrapper != null && windowWrapper.getWindow() != null) {
            if (mWindows != null) {
                mWindows.remove(windowWrapper);
            }
        }
    }


    /**
     * 展示弹窗
     * 从优先级最高的Window开始显示
     */
    public synchronized void show(Activity activity) {
        WindowWrapper windowWrapper = getMaxPriorityWindow();
        if (windowWrapper != null && windowWrapper.isCanShow()) {
            IWindow window = windowWrapper.getWindow();
            if (window != null) {
                window.show(activity);
            }
        }
    }


    /**
     * 显示指定的弹窗
     *
     * @param priorities
     */
    public synchronized void show(Activity activity, int priorities) {
        WindowWrapper windowWrapper = getTargetWindow(priorities);
        if (windowWrapper != null && windowWrapper.getWindow() != null) {
            WindowWrapper topShowWindow = getShowingWindow();
            if (topShowWindow == null) {
                int priority = windowWrapper.getPriority();
                WindowWrapper maxPriorityWindow = getMaxPriorityWindow();
                if (maxPriorityWindow != null && windowWrapper.isCanShow() && priority >= maxPriorityWindow.getPriority()) {
                    if (windowWrapper.getWindow() != null) {
                        windowWrapper.getWindow().show(activity);
                    }
                }
            }
        }
    }


    /**
     * 清除弹窗管理者
     */
    public synchronized void clear() {
        if (mWindows != null) {
            for (int i = 0, size = mWindows.size(); i < size; i++) {
                if (mWindows.get(i) != null) {
                    IWindow window = mWindows.get(i).getWindow();
                    if (window != null) {
                        window.dismiss();
                    }
                }
            }
            mWindows.clear();
        }
        WindowHelper.getInstance().onDestroy();
    }


    /**
     * 清除弹窗管理者
     *
     * @param dismiss 是否同时dismiss掉弹窗管理者维护的弹窗
     */
    public synchronized void clear(boolean dismiss) {
        if (mWindows != null) {
            if (dismiss) {
                for (int i = 0, size = mWindows.size(); i < size; i++) {
                    if (mWindows.get(i) != null) {
                        IWindow window = mWindows.get(i).getWindow();
                        if (window != null) {
                            window.dismiss();
                        }
                    }
                }
            }
            mWindows.clear();
        }
        WindowHelper.getInstance().onDestroy();
    }


    /**
     * 展示下一个优先级最大的Window
     */
    private synchronized void showNext(Activity activity) {
        WindowWrapper windowWrapper = getMaxPriorityWindow();
        if (windowWrapper != null && windowWrapper.isCanShow()) {
            if (windowWrapper.getWindow() != null) {
                windowWrapper.getWindow().show(activity);
            }
        }
    }


    /**
     * 获取当前栈中优先级最高的Window(优先级相同则返回后添加的弹窗)
     */
    private synchronized WindowWrapper getMaxPriorityWindow() {
        if (mWindows != null) {
            int maxPriority = -1;
            int position = -1;
            for (int i = 0, size = mWindows.size(); i < size; i++) {
                WindowWrapper windowWrapper = mWindows.get(i);
                if (i == 0) {
                    position = 0;
                    maxPriority = windowWrapper.getPriority();
                } else {
                    if (windowWrapper.getPriority() >= maxPriority) {
                        position = i;
                        maxPriority = windowWrapper.getPriority();
                    }
                }
            }
            if (position != -1) {
                return mWindows.get(position);
            } else {
                return null;
            }
        }
        return null;
    }


    private synchronized WindowWrapper getTargetWindow(int priority) {
        if (mWindows != null) {
            for (int i = 0, size = mWindows.size(); i < size; i++) {
                WindowWrapper windowWrapper = mWindows.get(i);
                if (windowWrapper != null && windowWrapper.getPriority() == priority) {
                    return windowWrapper;
                }
            }
        }
        return null;
    }


    /**
     * 获取当前处于show状态的弹窗
     */
    private synchronized WindowWrapper getShowingWindow() {
        if (mWindows != null) {
            for (int i = 0, size = mWindows.size(); i < size; i++) {
                WindowWrapper windowWrapper = mWindows.get(i);
                if (windowWrapper != null && windowWrapper.getWindow() != null && windowWrapper.getWindow().isShowing()) {
                    return windowWrapper;
                }
            }
        }
        return null;
    }

}
Copy the code

The WindowTaskManager class has three main methods:

  • addWindow(Activity activity, WindowWrapper windowWrapper)
  • enableWindow(Activity activity, int priority, IWindow window)
  • disableWindow(int priority)
  • setBlockTask(boolean show)

Dialogs that need to be displayed sequentially are uniformly added using the addWindow method, which is called before the network request is made. The function tells WindowTaskManager how many popovers to display in order. When the network request returns, the enableWindow method is called to display the popover if it is needed, and the disableWindow method is called to remove the popover from the display queue if it is not needed.

In addition, sometimes it is necessary to block the display of pop-ups. For example, after the system permission is enabled, the system permission authorization interface will be displayed, and other pop-ups will continue to be displayed after the authorization is completed. SetBlockTask is called to set whether the popover task will pause or continue.

The above is the main logic in order to display the popover, using the form inherit IWindow first, to achieve the relevant method. You can then do this by manipulating the WindowTaskManager class. The code is for reading only, see the project for details.

Project address: github.com/Geekince/Pr…

Eggs:

If a DialogFragment needs to be displayed in a DialogFragment, you are advised to enable the display in the Disappearance callback of the DialogFragment rather than directly. Since getChildFragmentManager may fail when a DialogFragment disappears, you should use getFragmentManager on the outer layer.