1、定义
观察者模式就是定义对象间的一种一对多的依赖关系。当被观察者(Observable)发生改变,所有依赖与它的对象(观察者,Observer)都会得到通知并自动更新。
2、分析BaseAdapter
观察者模式是我们常接触的一种设计模式,比如经常使用的ListVIew的BaseAdapter使用的就是观察者模式。
public abstract class BaseAdapter implements ListAdapter, SpinnerAdapter {
private final DataSetObservable mDataSetObservable = new DataSetObservable();
public void registerDataSetObserver(DataSetObserver observer) {
mDataSetObservable.registerObserver(observer);
}
public void unregisterDataSetObserver(DataSetObserver observer) {
mDataSetObservable.unregisterObserver(observer);
}
/**
* Notifies the attached observers that the underlying data has been changed
* and any View reflecting the data set should refresh itself.
*/
public void notifyDataSetChanged() {
mDataSetObservable.notifyChanged();
}
。。。
}
1、通知数据的改变
当数据发生改变的时候,我们通常会调用BaseAdapter的notifyDataSetChanged(),通知所有的观察者:通过遍历所有的观察者(mObservers),并调用其onChanged()来通知观察者。
public class DataSetObservable extends Observable {
public void notifyChanged() {
synchronized(mObservers) {
for (int i = mObservers.size() - 1; i >= 0; i--) {
mObservers.get(i).onChanged();
}
}
}
。。。
}
但是观察者是从哪里来的呢?
2、注册观察者
这些观察者(Observer)是在setAdapter()的时候创建并注册到被观察者(Observable)的。
public class ListView extends AbsListView {
/**
* Should be used by subclasses to listen to changes in the dataset
*/
AdapterDataSetObserver mDataSetObserver;
/**
* The adapter containing the data to be displayed by this view
*/
ListAdapter mAdapter;
。。。
@Override
public void setAdapter(ListAdapter adapter) {
if (mAdapter != null && mDataSetObserver != null) {
mAdapter.unregisterDataSetObserver(mDataSetObserver);
}
。。。
mAdapter = adapter;
if (mAdapter != null) {
mDataSetObserver = new AdapterDataSetObserver();
mAdapter.registerDataSetObserver(mDataSetObserver);
。。。
}
requestLayout();
}
}
其中AdapterDataSetObserver在ListView的父类中,并在onChanged()被调用的时候,调用requestLayout()重新布局listView。
class AdapterDataSetObserver extends DataSetObserver {
@Override
public void onChanged() {
。。。
requestLayout();
}
@Override
public void onInvalidated() {
。。。
requestLayout();
}
}
所以,当ListVIew数据发生改变的时候,调用Adapter的notifyDataSetChanged()--->DataSetObservable (notifyChanged())--->DataSetObserver(onChanged()),总之,最终调用了所有观察者的onChanged()方法,在onChanged()方法中又会调用ListVIew的 requestLayout()函数,重新布局ListView。
其中Observable
public abstract class Observable {
/**
* The list of observers. An observer can be in the list at most
* once and will never be null.
*/
protected final ArrayList mObservers = new ArrayList();
/**
* 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);
}
}
。。。
}
DataSetObserver
public abstract class DataSetObserver {
/**
* This method is called when the entire data set has changed,
* most likely through a call to {@link Cursor#requery()} on a {@link Cursor}.
*/
public void onChanged() {
// Do nothing
}
/**
* This method is called when the entire data becomes invalid,
* most likely through a call to {@link Cursor#deactivate()} or {@link Cursor#close()} on a
* {@link Cursor}.
*/
public void onInvalidated() {
// Do nothing
}
}
3、例子
使用方式和ListView一样
public class CommonHorizontalListView extends HorizontalScrollView {
private ListAdapter mAdapter;
private AdapterDataObserver mObserver;
private LinearLayout mContainer;
private Context mContext;
private int paddingLeft;
private int paddingRight;
private int paddingTopBottom;
private int leftItemMargin;
private int rightItemMargin;
private float density;
public CommonHorizontalListView(Context context) {
this(context, null);
}
public CommonHorizontalListView(Context context, AttributeSet attrs) {
super(context, attrs);
this.mContext = context;
density = context.getResources().getDisplayMetrics().density;
init();
}
private void init() {
paddingLeft = (int) (10 * density);
paddingRight = (int) (10 * density);
paddingTopBottom = (int) (3 * density);
leftItemMargin= (int) (5 * density);
rightItemMargin= (int) (5 * density);
mContainer = new LinearLayout(mContext);
mContainer.setOrientation(LinearLayout.HORIZONTAL);
LayoutParams p = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
mContainer.setPadding(paddingLeft, paddingTopBottom, paddingRight, paddingTopBottom);
addView(mContainer, p);
setBackgroundColor(Color.WHITE);
setSmoothScrollingEnabled(true);
setHorizontalScrollBarEnabled(false);
}
public void setAdapter(ListAdapter adapter) {
if (mAdapter != null && mObserver != null) {
mAdapter.unregisterDataSetObserver(mObserver);
}
if (adapter != null) {
this.mAdapter = adapter;
mObserver = new AdapterDataObserver();
mAdapter.registerDataSetObserver(mObserver);
addViews();
}
}
private void addViews() {
mContainer.removeAllViews();
int itemCount = mAdapter.getCount();
for (int i = 0; i < itemCount; i++) {
View child = mAdapter.getView(i, null, null);
LinearLayout.LayoutParams params=new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
params.leftMargin=leftItemMargin;
params.rightMargin=rightItemMargin;
mContainer.addView(child,params);
}
}
private class AdapterDataObserver extends DataSetObserver {
@Override
public void onChanged() {
addViews();
//requestLayout();
}
@Override
public void onInvalidated() {
//addViews();
//requestLayout();
}
}
}
注意:requeLayout() : 控件会重新执行 onMesure() 、onLayout() ,重新测量和定位。
3、分析EventBus
EventBus,事件总线,它使用发布订阅模式支持组件之间的通信,不需要显式地注册回调,比观察者模式更灵活,可用于替换Java中传统的事件监听器。
1、自己实现简单的事件总线
定义一个订阅者列表(Map
method.invoke(target,args);
为了灵活的定义方法接收器,可以使用注解。
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Subscriber {
}
使用方法
EventBus.getInstance().subscribe(MainActivity.this);
EventBus.getInstance().unsubscribe(this);
EventBus.getInstance().publish("update from SecondFragment");
@Subscriber
public void onEventMainThread(String str){
Toast.makeText(this,"MainActivity --- "+ str,Toast.LENGTH_LONG).show();
}
public class EventBus {
//订阅者列表
private Map,ArrayList> subscriptionByEvent=new HashMap<>();
private EventBus(){
}
public static EventBus getInstance(){
return Singleton.INSTANCE;
}
static class Singleton {
static EventBus INSTANCE=new EventBus();
}
// register(target) 方法用于注册事件接收器的目标对象,我们需要保存这个对象,
// 同时还需要查找这个对象中存在的事件接收器方法
public void subscribe(Object target){
Class> clazz=target.getClass();
Method[] methods=clazz.getMethods();
for (Method method:methods){
Subscriber subscriber=method.getAnnotation(Subscriber.class);
if (subscriber!=null){
Class[] parameters=method.getParameterTypes();
if (parameters!=null && parameters.length==1){
ArrayList subscriptions;
if (subscriptionByEvent.containsKey(parameters[0])){
subscriptions = subscriptionByEvent.get(parameters[0]);
}else {
subscriptions =new ArrayList<>();
}
EventSubscription subscription =new EventSubscription(target,method,parameters[0]);
subscriptions.add(subscription);
subscriptionByEvent.put(parameters[0], subscriptions);
}
}
// if (method.getName().equals("onEventMainThread")){
// Class[] parameters=method.getParameterTypes();
// ArrayList subscriptions;
// if (subscriptionByEvent.containsKey(parameters[0])){
// subscriptions = subscriptionByEvent.get(parameters[0]);
// }else {
// subscriptions =new ArrayList<>();
// }
// EventSubscription subscription =new EventSubscription(target,method,parameters[0]);
// subscriptions.add(subscription);
// subscriptionByEvent.put(parameters[0], subscriptions);
// }
}
}
//取消注册目标对象
public void unsubscribe(Object target){
Class> clazz=target.getClass();
Method[] methods=clazz.getMethods();
for (Method method:methods){
Subscriber subscriber=method.getAnnotation(Subscriber.class);
if (subscriber!=null){
Class[] parameters=method.getParameterTypes();
if (parameters!=null && parameters.length==1){
if (subscriptionByEvent.containsKey(parameters[0])){
subscriptionByEvent.remove(parameters[0]);
}
}
}
// if (method.getName().equals("onEventMainThread")){
// Class[] parameters=method.getParameterTypes();
// ArrayList eventObservers;
// if (subscriptionByEvent.containsKey(parameters[0])){
// subscriptionByEvent.remove(parameters[0]);
// }
// }
}
}
// 发送事件给 目标对象和事件接收器(onEventMainThread)方法。
public void publish(Object event){
Class> clazz=event.getClass();
if (subscriptionByEvent.containsKey(clazz)){
ArrayList subscriptions =subscriptionByEvent.get(clazz);
for (EventSubscription eventObserver : subscriptions){
eventObserver.onChanged(event);
}
}
}
}
2、EventBus解析
参考:
Android源码设计模式、教你自己实现一个事件总线EventBus、跟我一起写EventBus(一)、 Android事件总线(一)EventBus3.0用法全解析、