Android 应用开发中的观察者模式
在我们做Android应用的时候,会大量使用观察者模式,因为Framework层里面的事件驱动都是基于观察者模式实现的。另外在Framework层里面的各种服务在数据变更的时候,也是通过观察者模式实现上层数据更新。下面会讲两个例子来说明:
A)控件中Listener监听方式
Android里面最典型的观察者就是我们使用的各种控件监听者。例如下面对某个按钮的监听:
//Edited by mythou
//http://www.cnblogs.com/mythou/
Button baiduclickButton = (Button)findViewById(R.id.button1);
//注册观察者
baiduclickButton.setOnClickListener(new OnClickListener()
{
//观察者实现
@Override
public void onClick(View arg0)
{
Log.d("Mythou_Log", "Click the button ");
}
});
例如上面的代码,注册了一个按钮的监听方法。这里实际上是应用了一对一的观察者模式,setOnClickListener()方法就是注册一个观察者,Button对象就是我们要观察的目标对象。而new出来的OnClickListener(),就是我们实际的观察者。
每当我们的目标按钮对象被点击,状态发生变化的时候,就会通过回调注册的OnClickListener观察者的onClick方法会来通知观察者,Button状态发生变化。这里的onClick相当于前面例子里面的update方法。下面是Android源码里面对OnClickListener的定义,跟我们前面定义一个观察者接口类似。
//Edited by mythou
//http://www.cnblogs.com/mythou/
public interface OnClickListener
{
/**
* Called when a view has been clicked.
*
* @param v The view that was clicked.
*/
void onClick(View v);
}
B)GPS位置信息监听
上面对按钮监听是属于一对一的观察者模式,当然你也可以用一个Listener监听多个按钮。下面我们再讲一个标准的一对多的观察者模式的应用。在我们使用GPS模块的时候,需要监听GPS模块位置变化,通常我们会编写下面代码:
//Edited by mythou
//http://www.cnblogs.com/mythou/
// 通过GPS定位
String LocateType= locationManager.GPS_PROVIDER;
Location location = locationManager.getLastKnownLocation(LocateType);
// 设置监听器,设置自动更新间隔这里设置1000ms,移动距离:0米。
locationManager.requestLocationUpdates(provider, 1000, 0, locationListener);
// 设置状态监听回调函数。statusListener是监听的回调函数。
locationManager.addGpsStatusListener(statusListener);
//监听器实现
private final GpsStatus.Listener statusListener = new GpsStatus.Listener()
{
public void onGpsStatusChanged(int event)
{
// GPS状态变化时的回调,获取当前状态
GpsStatus status = locationManager.getGpsStatus(null);
//自己编写的方法,获取卫星状态相关数据
GetGPSStatus(event, status);
}
};
GPS位置服务是Framework的一个系统层服务,整个系统只有一个运行的实例。但实际使用时,可能会出现好几个应用都在使用这个服务,因此会形成了一个一对多的观察者例子。这里不对代码进行深入对比讲解,只要对照上面的讲解,你就可以把目标对象、观察者接口、观察者实现、数据更新回调接口找出来。有兴趣的朋友还可以追查Android的源码,看看GpsStatus里面的具体实现。
5、结语
除了上面说的按钮响应、GPS服务外,还有一个例子比较经典,就是我们的BroadcastReceiver响应,也是基于观察者模式来实现,下面总结里面也会说到,观察者模式支持广播通信。有关BroadcastReceiver是怎么实现观察者模式的,有兴趣的朋友可以自己对比代码,和查看Android实现源码,自己动手才能加深印象。引入设计模式是为了对系统有更深入的理解。下面总结一下观察者模式的优缺点,方便我们在使用的时候,可以根据实际情况衡量。
A)优点
- 实现观察者和目标对象之间的抽象耦合。
- 观察者模式支持广播通信。被观察者会所有的登记过的观察者发出通知。
B)缺点
- 可能会引起多余的数据通知。
- 可能会导致通知数据循环,导致死锁产生。
JAVA 观察者模式
观察者模式的组成
抽象主题角色:把所有对观察者对象的引用保存在一个集合中,每个抽象主题角色都可以有任意数量的观察者。抽象主题提供一个接口,可以增加和删除观察者角色。一般用一个抽象类和接口来实现。
抽象观察者角色:为所有具体的观察者定义一个接口,在得到主题的通知时更新自己。
具体主题角色:在具体主题内部状态改变时,给所有登记过的观察者发出通知。具体主题角色通常用一个子类实现。
具体观察者角色:该角色实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态相协调。通常用一个子类实现。如果需要,具体观察者角色可以保存一个指向具体主题角色的引用。
程序实例
通过程序实例来说明观察者模式:
首先定义抽象的观察者:
//抽象观察者角色
public interface Watcher
{
public void update(String str);
}
然后定义抽象的主题角色,即抽象的被观察者,在其中声明方法(添加、移除观察者,通知观察者):
//抽象主题角色,watched:被观察
public interface Watched
{
public void addWatcher(Watcher watcher);
public void removeWatcher(Watcher watcher);
public void notifyWatchers(String str);
}
然后定义具体的观察者:
public class ConcreteWatcher implements Watcher
{
@Override
public void update(String str)
{
System.out.println(str);
}
}
之后是具体的主题角色:
import java.util.ArrayList;
import java.util.List;
public class ConcreteWatched implements Watched
{
// 存放观察者
private List<Watcher> list = new ArrayList<Watcher>();
@Override
public void addWatcher(Watcher watcher)
{
list.add(watcher);
}
@Override
public void removeWatcher(Watcher watcher)
{
list.remove(watcher);
}
@Override
public void notifyWatchers(String str)
{
// 自动调用实际上是主题进行调用的
for (Watcher watcher : list)
{
watcher.update(str);
}
}
}
编写测试类:
public class Test
{
public static void main(String[] args)
{
Watched girl = new ConcreteWatched();
Watcher watcher1 = new ConcreteWatcher();
Watcher watcher2 = new ConcreteWatcher();
Watcher watcher3 = new ConcreteWatcher();
girl.addWatcher(watcher1);
girl.addWatcher(watcher2);
girl.addWatcher(watcher3);
girl.notifyWatchers("开心");
}
}