«

Android设计模式--观察者模式

时间:2024-3-2 18:40     作者:韩俊     分类: Android


问题:

在Android中,根据Android的事件树,我们知道:在与屏幕按键、触摸、滑动等操作与应用进行交互时触发的相关事件中,交互事件是沿着事件树自顶向下传播的;

当位于事件树上层的父控件接受到事件后,判断事件的所属,若需要,则截获事件,否则,向下子控件传播。


那么我们在编写各种Listener,在View各种事件函数接受和处理各类交互事件,这种处理模式,是否就是一种观察者模式呢?


问题,先放于此处。

言归正传:

观察者模式:


1、定义:

Define a one-to-many dependency between objects so that when one object changes state, all its dependents aer notified and updated automatically.
定义对象间一种一对多的依赖关系,使得当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新。


2、适用:
当一个对象的改变需要同时改变其他对象的时候,并且他不知道有多少对象需要改变的时候,考虑使用观察者模式;


3、目的:

观察者模式所做的工作其实就是在解耦合,让耦合的双方都依赖与抽象,而不依赖于具体使得双方的变化都不影响另一方的变化;


4、原则:

观察者模式符合依赖倒转原则;


5、其他:

观察者模式是一种对象的行为模式,又叫发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式或从属者(Dependents)模式。


6、简单的demo:

demo 的业务是:一个按钮对象,当按钮点击时,通知两个视图的改变;

首先是:观察者:

package com.example.demo.Observer;
/**
 * 抽象观察者(Observer)角色
 * @author qubian
 * @data 2015年6月11日
 * @email naibbian@163.com
 *
 */
public interface Observer {

    public void upadteView(String info);
}
package com.example.demo.Observer;

import android.util.Log;
/**
 * 具体观察者角色
 * @author qubian
 * @data 2015年6月11日
 * @email naibbian@163.com
 *
 */
public class Observer_View1 implements Observer{

    @Override
    public void upadteView(String info) {
        Log.i("upadteView", "Observer_View1,视图1发生变化,变化的内容是:"+info);

    }

}
package com.example.demo.Observer;

import android.util.Log;
/**
 * 具体观察者角色
 * @author qubian
 * @data 2015年6月11日
 * @email naibbian@163.com
 *
 */
public class Observer_View2  implements Observer{

    @Override
    public void upadteView(String info) {
        Log.i("upadteView", "Observer_View2,视图2发生变化,变化的内容是:"+info);
    }

}

主题角色:

package com.example.demo.Observer;

import java.util.ArrayList;
import java.util.List;

/**
 * 抽象主题(Subject)角色
 * @author qubian
 * @data 2015年6月11日
 * @email naibbian@163.com
 *
 */
public abstract class Subject {

    private List<Observer> list;
    /**
     * 添加观察者,面向接口,面向抽象编程
     * @param observer
     */
    public void  addObserver(Observer observer)
    {
        if (list==null) {
            list = new ArrayList<Observer>();
        }
        list.add(observer);
    }
    /**
     * 通知视图改变
     * @param info
     */
    public void notifyDataSetChange(String info)
    {
        for (Observer observer : list) {
            observer.upadteView(info);
        }
    }

}
package com.example.demo.Observer;

import android.util.Log;
/**
 * 具体被观察者角色
 * 比如说我,点击了按钮,我希望,视图发生变化
 * @author qubian
 * @data 2015年6月11日
 * @email naibbian@163.com
 *
 */
public class Subject_Button extends Subject{

    /**
     * 点击了按钮,我希望,视图发生变化
     */
    public void Click()
    {
        Log.i("Subject_Button", "点击了按钮");

        String tag ="101";
        notifyDataSetChange(tag);
    }

}

使用:

package com.example.demo.Observer;

/**
 *  使用
 * @author qubian
 * @data 2015年6月11日
 * @email naibbian@163.com
 *
 */
public class UseObserver {

    public void use()
    {
        // 业务是这样的:我,点击了按钮,我希望绑定在这个按钮上的视图发生变化

        // 首先 是有两个视图的观察者:

        Observer  obj1 = new Observer_View1();
        Observer  obj2 = new Observer_View2();

        // 按钮
        Subject_Button sub = new Subject_Button();
        sub.addObserver(obj1);
        sub.addObserver(obj2);
        // 点击按钮 视图变化
        sub.Click();
    }
}

7、java库:

在java中的java.util库里面,提供了一个Observable类以及一个Observer接口,构成java语言对观察者模式的支持。

使用比较简单,具体观察对象实现Observer接口,被观察者继承Observable类,即可。

比较简单,不再说明了;

/*
 *  Licensed to the Apache Software Foundation (ASF) under one or more
 *  contributor license agreements.  See the NOTICE file distributed with
 *  this work for additional information regarding copyright ownership.
 *  The ASF licenses this file to You under the Apache License, Version 2.0
 *  (the "License"); you may not use this file except in compliance with
 *  the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

package java.util;

/**
 * {@code Observer} is the interface to be implemented by objects that
 * receive notification of updates on an {@code Observable} object.
 *
 * @see Observable
 */
public interface Observer {

    /**
     * This method is called if the specified {@code Observable} object's
     * {@code notifyObservers} method is called (because the {@code Observable}
     * object has been updated.
     *
     * @param observable
     *            the {@link Observable} object.
     * @param data
     *            the data passed to {@link Observable#notifyObservers(Object)}.
     */
    void update(Observable observable, Object data);
}

package android.database;

import java.util.ArrayList;

/**
 * Provides methods for registering or unregistering arbitrary observers in an {@link ArrayList}.
 *
 * This abstract class is intended to be subclassed and specialized to maintain
 * a registry of observers of specific types and dispatch notifications to them.
 *
 * @param T The observer type.
 */
public abstract class Observable<T> {
    /**
     * The list of observers.  An observer can be in the list at most
     * once and will never be null.
     */
    protected final ArrayList<T> mObservers = new ArrayList<T>();

    /**
     * Adds an observer to the list. The observer cannot be null and it must not already
     * be registered.
     * @param observer the observer to register
     * @throws IllegalArgumentException the observer is null
     * @throws IllegalStateException the observer is already registered
     */
    public void registerObserver(T observer) {
        if (observer == null) {
            throw new IllegalArgumentException("The observer is null.");
        }
        synchronized(mObservers) {
            if (mObservers.contains(observer)) {
                throw new IllegalStateException("Observer " + observer + " is already registered.");
            }
            mObservers.add(observer);
        }
    }

    /**
     * Removes a previously registered observer. The observer must not be null and it
     * must already have been registered.
     * @param observer the observer to unregister
     * @throws IllegalArgumentException the observer is null
     * @throws IllegalStateException the observer is not yet registered
     */
    public void unregisterObserver(T observer) {
        if (observer == null) {
            throw new IllegalArgumentException("The observer is null.");
        }
        synchronized(mObservers) {
            int index = mObservers.indexOf(observer);
            if (index == -1) {
                throw new IllegalStateException("Observer " + observer + " was not registered.");
            }
            mObservers.remove(index);
        }
    }

    /**
     * Remove all registered observers.
     */
    public void unregisterAll() {
        synchronized(mObservers) {
            mObservers.clear();
        }
    }
}

8、android的运用:

回归到,上面的问题;

很明显,上述的Android事件树的传递,交互事件的监听,我们所写的Listener回调,整个监听部分就是一种观察者模式。


在我们最熟悉的点击事件中,初始化时,我们设置视图的监听:


    /**
     * Register a callback to be invoked when this view is clicked. If this view is not
     * clickable, it becomes clickable.
     *
     * @param l The callback that will run
     *
     * @see #setClickable(boolean)
     */
    public void setOnClickListener(OnClickListener l) {
        if (!isClickable()) {
            setClickable(true);
        }
        getListenerInfo().mOnClickListener = l;
    }

OnClickListener接口的描述:

    /**
     * Interface definition for a callback to be invoked when a view is clicked.
     */
    public interface OnClickListener {
        /**
         * Called when a view has been clicked.
         *
         * @param v The view that was clicked.
         */
        void onClick(View v);
    }

OnclickListener 是在View 视图内部类ListenerInfo中:

static class ListenerInfo {

        protected OnFocusChangeListener mOnFocusChangeListener;

        private ArrayList<OnLayoutChangeListener> mOnLayoutChangeListeners;

        private CopyOnWriteArrayList<OnAttachStateChangeListener> mOnAttachStateChangeListeners;

        /**
         * Listener used to dispatch click events.
         * This field should be made private, so it is hidden from the SDK.
         * {@hide}
         */
        public OnClickListener mOnClickListener;

        protected OnLongClickListener mOnLongClickListener;

        protected OnCreateContextMenuListener mOnCreateContextMenuListener;

        private OnKeyListener mOnKeyListener;

        private OnTouchListener mOnTouchListener;

        private OnHoverListener mOnHoverListener;

        private OnGenericMotionListener mOnGenericMotionListener;

        private OnDragListener mOnDragListener;

        private OnSystemUiVisibilityChangeListener mOnSystemUiVisibilityChangeListener;
    }

调用:

    public boolean performClick() {
        sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);

        ListenerInfo li = mListenerInfo;
        if (li != null && li.mOnClickListener != null) {
            playSoundEffect(SoundEffectConstants.CLICK);
            li.mOnClickListener.onClick(this);
            return true;
        }

        return false;
    }
    public boolean callOnClick() {
        ListenerInfo li = mListenerInfo;
        if (li != null && li.mOnClickListener != null) {
            li.mOnClickListener.onClick(this);
            return true;
        }
        return false;
    }

至于PerformClick的调用,则是在视图的监听OnTouchEvent等有具体的体现:

 public boolean onTouchEvent(MotionEvent event) {

        if (((viewFlags & CLICKABLE) == CLICKABLE ||
                (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)) {
            switch (event.getAction()) {
                case MotionEvent.ACTION_UP:
                    boolean prepressed = (mPrivateFlags & PFLAG_PREPRESSED) != 0;
                    if ((mPrivateFlags & PFLAG_PRESSED) != 0 || prepressed) {
                        // take focus if we don't have it already and we should in
                        // touch mode.
                        boolean focusTaken = false;
                        if (isFocusable() && isFocusableInTouchMode() && !isFocused()) {
                            focusTaken = requestFocus();
                        }

                        if (prepressed) {
                            // The button is being released before we actually
                            // showed it as pressed.  Make it show the pressed
                            // state now (before scheduling the click) to ensure
                            // the user sees it.
                            setPressed(true);
                       }

                        if (!mHasPerformedLongPress) {
                            // This is a tap, so remove the longpress check
                            removeLongPressCallback();

                            // Only perform take click actions if we were in the pressed state
                            if (!focusTaken) {
                                // Use a Runnable and post this rather than calling
                                // performClick directly. This lets other visual state
                                // of the view update before click actions start.
                                if (mPerformClick == null) {
                                    mPerformClick = new PerformClick();
                                }
                                if (!post(mPerformClick)) {
                                    performClick();
                                }
                            }
                        }

                        if (mUnsetPressedState == null) {
                            mUnsetPressedState = new UnsetPressedState();
                        }

                        if (prepressed) {
                            postDelayed(mUnsetPressedState,
                                    ViewConfiguration.getPressedStateDuration());
                        } else if (!post(mUnsetPressedState)) {
                            // If the post failed, unpress right now
                            mUnsetPressedState.run();
                        }
                        removeTapCallback();
                    }
                    break;

                case MotionEvent.ACTION_DOWN:

                    break;

                case MotionEvent.ACTION_CANCEL:

                case MotionEvent.ACTION_MOVE:

                    break;
            }
            return true;
        }

        return false;
    }


标签: android

热门推荐