[Android] PendingAction 实现“等待某些条件满足后执行”的一种超轻量级的框架

public class Main {

    public static void main(String[] args) {
        /*
        PendingAction是解决经常遇到的“等待某些条件满足后执行”case的一种超轻量级的框架。
        例如,某代码逻辑在绑定后台成功后执行一次/某代码逻辑在连上服务器后执行一次。注意如果要执行多次(即当成订阅模式使用)时,
        action handler的removeAfterRun要设置为false
         */
        // 1. 首先,创建一个PendingAction对象。一般情况下,一个业务场景只有一个这样的对象。
        PendingAction pendingAction = new PendingAction();
        // 2. 创建action handler,表明当条件满足时,你要做些什么。
        PendingAction.createActionHandler()
                .doOnce(() -> { // 这里写你要执行的代码
                    System.out.println("A doOnce called");
                })
//                .removeAfterRun(true) // 设置是否执行完一次就销毁。默认是。
                .waitAll(Event.A, Event.B) // 等待 A B 全部执行(and)
                .waitOne(Event.E, Event.F) // 等待 E F 其中一个执行(or)
                .attachTo(pendingAction); // 将handler注入到之前创建的PendingAction对象中

        System.out.println("add A");
        pendingAction.addEvent(Event.A);
        System.out.println("add B");
        // 运行完这一句后,A、B都执行过,上面的handler会执行,打印"A doOnce called"
        pendingAction.addEvent(Event.B);

        System.out.println("add C");
        // 注意!运行完这一句后,A、B、C都执行过,如果removeAfterRun为false,
        // 那么上面的handler会执行,打印"A doOnce called"
        pendingAction.addEvent(Event.C);

        System.out.println("set C");
        // 这里用了setEvent,表示重置内部的event状态,上面的A、B event会被清掉
        pendingAction.setEvent(Event.C);

        System.out.println("remove BC");
        // 可以remove掉指定的event
        pendingAction.removeEvent(Event.B, Event.C, Event.A);

        System.out.println("add E");
        // 运行完这一句后,E或者F执行过。但是!由于默认removeAfterRun为true,
        // handler已经销毁,所以这里并不会打印"A doOnce called"
        pendingAction.addEvent(Event.E);

        System.out.println("clear");
        pendingAction.clear();
    }

    private enum Event {
        A, B, C, D, E, F, G
    }
}

源码如下所示:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class PendingAction {

    private Set<Enum<?>> mEvents = new HashSet<>();

    private List<ActionHandler> mActionHandlers = new ArrayList<>();

    ///////////////////////////////////public///////////////////////////////////

    public synchronized void addHandler(ActionHandler actionHandler) {
        mActionHandlers.add(actionHandler);
        if (runHandler(actionHandler) && actionHandler.mAutoRemove) {
            mActionHandlers.remove(actionHandler);
        }
    }

    public synchronized void addEvent(Enum<?> event) {
        mEvents.add(event);
        for (ActionHandler actionHandler : new ArrayList<>(mActionHandlers)) {
            if (runHandler(actionHandler) && actionHandler.mAutoRemove) {
                mActionHandlers.remove(actionHandler);
            }
        }
    }

    public synchronized void clear() {
        mEvents.clear();
        mActionHandlers.clear();
    }

    public synchronized void removeEvent(Enum<?> ... states) {
        mEvents.removeAll(Arrays.asList(states));
    }

    public synchronized void setEvent(Enum<?> ... states) {
        mEvents.clear();
        for (Enum<?> state : states) {
            addEvent(state);
        }
    }

    public synchronized Set<Enum<?>> getEvents() {
        return new HashSet<>(mEvents);
    }

    //////////////////////////////////////////////////////////////////////

    public static synchronized ActionHandler createActionHandler() {
        ActionHandler newActionHandler = new ActionHandler();
        return newActionHandler;
    }

    ///////////////////////////////////private///////////////////////////////////

    private synchronized boolean runHandler(ActionHandler actionHandler) {
        if (actionHandler.isMatch(mEvents)) {
            actionHandler.run();
            return true;
        }
        return false;
    }

    ///////////////////////////////////state///////////////////////////////////

    public static class ActionHandler {

        private Runnable mRunnable;

        private List<MatchStrategy> mMatchStrategyList = new ArrayList<>();

        private boolean mAutoRemove = true;

        private ActionHandler() {
        }

        public synchronized ActionHandler doOnce(Runnable runnable) {
            mRunnable = runnable;
            return this;
        }

        public synchronized ActionHandler waitAll(Enum<?> ... waitTargets) {
            Set<Enum<?>> targetSet = new HashSet<>(Arrays.asList(waitTargets));
            mMatchStrategyList.add(collection -> collection.size() > 0 && targetSet.containsAll(collection));
            return this;
        }

        public ActionHandler waitOne(Enum<?> ... waitTargets) {
            // 求交集,每次都新建一个
            mMatchStrategyList.add(states -> {
                Set<Enum<?>> temp = new HashSet<>(Arrays.asList(waitTargets));
                temp.retainAll(states);
                return temp.size() > 0;
            });
            return this;
        }

        public synchronized ActionHandler removeAfterRun(boolean autoRemove) {
            mAutoRemove = autoRemove;
            return this;
        }

        public void attachTo(PendingAction action) {
            assert action != null;
            action.addHandler(this);
        }

        void run() {
            if (mRunnable != null) {
                mRunnable.run();
            }
        }

        boolean isMatch(Set<Enum<?>> states) {
            return mMatchStrategyList.stream().anyMatch(matchStrategy -> matchStrategy.isMatch(states));
        }
    }

    private interface MatchStrategy {
        boolean isMatch(Set<Enum<?>> states);
    }
}

当然,你可以用RxJava来实现 😉