美文网首页
观察者模式实战——登录页面

观察者模式实战——登录页面

作者: tinyvampirepudg | 来源:发表于2019-07-13 06:58 被阅读0次

    观察者模式实战——登录页面

    Android开发中我们会遇到这样的需求,某个需要用户输入信息的页面,只有在用户输入了多条数据之后,下一步按钮才能可点击,用户才可以进行下一步操作。
    如下图所示,用户只有在同时输入了手机号和密码之后,登录按钮才可以点击,否则登录按钮不可点击。

    <img src="https://tinytongtong-1255688482.cos.ap-beijing.myqcloud.com/174E7AA801E9C7CB806DC587BF75E3C3.jpg" width=256/> <img src="https://tinytongtong-1255688482.cos.ap-beijing.myqcloud.com/B86D357A407E61E8B78A35BCE21B38FE.jpg" width=256/>

    这种需求在开发中很常见,当且仅当多个条件同时被满足,某个步骤才会执行。

    那么这个问题如何解决呢?第一眼看过去,这个是典型的观察者模式,那我们看下Java中观察者的相关实现。

    Java中定义了两个类供我们使用,java.util.Observer和java.util.Observable,代码如下:

    public interface Observer {
        void update(Observable o, Object arg);
    }
    
    public class Observable {
        private boolean changed = false;
        private Vector<Observer> obs;
    
        /** Construct an Observable with zero Observers. */
    
        public Observable() {
            obs = new Vector<>();
        }
    
        public synchronized void addObserver(Observer o) {
            if (o == null)
                throw new NullPointerException();
            if (!obs.contains(o)) {
                obs.addElement(o);
            }
        }
    
        public synchronized void deleteObserver(Observer o) {
            obs.removeElement(o);
        }
    
        public void notifyObservers() {
            notifyObservers(null);
        }
    
        ...
    }
    

    不过我们不能直接拿过来用,因为java.util.Observer和java.util.Observable中,观察者和被观察者是多对一的关系,一个Observable对应多个Observer,当Observable有变化时,会通知它持有的多个Observer。我们的需求是,多个被观察者对应一个观察者,当某个被观察者的数据变化时会通知观察者,此时观察者会检查所有被观察者的状态。这样,当所有被观察者的状态都满足条件时,观察者就会被通知到。

    好了,接下来我的代码实现:

    /**
     * @Description: 被观察者,单个View的输入状态,true or false
     * 参考 {@link java.util.Observable}
     * @Author wangjianzhou@qding.me
     * @Date 2018/11/29 2:06 PM
     * @Version v4.4
     */
    public class InputStatusObservable {
        private boolean ready;
        private InputStatusObserver observer;
    
        public InputStatusObservable(boolean ready, InputStatusObserverImpl observer) {
            this.ready = ready;
            this.observer = observer;
        }
    
        public InputStatusObservable(InputStatusObserverImpl observer) {
            this.observer = observer;
        }
    
        public boolean isReady() {
            return ready;
        }
    
        public void setReady(boolean ready) {
            this.ready = ready;
            observer.update();
        }
    }
    

    观察者接口:

    /**
     * @Description: 观察者
     * 参考 {@link java.util.Observer}
     * @Author wangjianzhou@qding.me
     * @Date 2018/11/29 2:06 PM
     * @Version v4.4
     */
    public interface InputStatusObserver {
        void update();
    }
    

    观察者实现:

    /**
     * @Description: 观察者实现,监听多个InputStatusObservable的状态。
     *
     * @Author wangjianzhou@qding.me
     * @Date 2018/11/29 2:06 PM
     * @Version v4.4
     */
    public class InputStatusObserverImpl implements InputStatusObserver {
        private ArrayList<InputStatusObservable> observableList = new ArrayList<>();
        private OnObservablesReadyListener onObservablesReadyListener;
    
        public InputStatusObserverImpl(OnObservablesReadyListener onObservablesReadyListener) {
            this.onObservablesReadyListener = onObservablesReadyListener;
        }
    
        public void add(InputStatusObservable observable) {
            observableList.add(observable);
        }
    
        public void remove(InputStatusObservable observable) {
            observableList.remove(observable);
        }
    
        /**
         * 所有InputStatusObservable的状态是否都已经Ok了
         *
         * @return
         */
        public boolean isObservablesReady() {
            for (InputStatusObservable observable : observableList) {
                if (!observable.isReady()) {
                    return false;
                }
            }
            return true;
        }
    
        @Override
        public void update() {
            if (onObservablesReadyListener != null) {
                onObservablesReadyListener.ready(isObservablesReady());
            }
        }
    
        public interface OnObservablesReadyListener {
            void ready(boolean isReady);
        }
    }
    

    下面介绍如何使用:
    1、定义观察者和被观察者,并对其进行绑定

    /**
             * 登录按钮是否可点击,依赖于是否输入了手机号码和密码
             */
            InputStatusObserverImpl.OnObservablesReadyListener bindReadyListener = new InputStatusObserverImpl.OnObservablesReadyListener() {
                @Override
                public void ready(boolean isReady) {
                    // isReady如果为true,表示所有被观察者的状态均为true。
                    finishBtn.setEnabled(isReady);
                    finishBtn.setOnClickListener(!isReady ? null : new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            login();
                        }
                    });
                }
            };
            // 定义观察者
            InputStatusObserverImpl observer = new InputStatusObserverImpl(bindReadyListener);
            //定义两个被观察者, 并将它们与观察者绑定。
            observablePhoneNum = new InputStatusObservable(observer);
            observer.add(observablePhoneNum);
            observablePwd = new InputStatusObservable(observer);
            observer.add(observablePwd);
    

    2、给EditText添加监听器。

        /**
         * 给手机号码、密码输入框添加监听器。当输入内容变化时,就更新被观察者的状态。
         */
        private void setEditTextListener() {
            // 给手机输入框添加监听
            compPhoneEt.addTextChangedListener(new TextWatcher() {
                @Override
                public void beforeTextChanged(CharSequence s, int start, int count, int after) {
    
                }
    
                @Override
                public void onTextChanged(CharSequence s, int start, int before, int count) {
    
                }
    
                @Override
                public void afterTextChanged(Editable s) {
                    observablePhoneNum.setReady(s.length() > 0);
                }
            });
            // 给密码输入框添加监听
            compPwdEt.addTextChangedListener(new TextWatcher() {
                @Override
                public void beforeTextChanged(CharSequence s, int start, int count, int after) {
    
                }
    
                @Override
                public void onTextChanged(CharSequence s, int start, int before, int count) {
    
                }
    
                @Override
                public void afterTextChanged(Editable s) {
                    observablePwd.setReady(s.length() > 0);
                }
            });
        }
    

    当然了,这个用rxJava的操作符也可以很容易的实现,这里就不废话了。

    项目地址,进入搜索ObserverLoginActivity即可。

    相关文章

      网友评论

          本文标题:观察者模式实战——登录页面

          本文链接:https://www.haomeiwen.com/subject/ljghkctx.html