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