问题:
在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; }