Android中的观察者模式

目录

 

定义

实例讲解

在Android源码中的运用

 1、ListView的Adapter

2、TextWatcher

3、BroadcastReceiver


定义

当一个对象改变状态时,则所有依赖于他的对象都会得到通知并自动更新。

被观察者采用注册-通知-注销来管理观察者。

概念Android中对应的类作用
观察者DataSetObserver用来响应变化,从而进行更改
被观察者DataSetObservable通知观察者进行改变,也可以称为观察者的管理者,对观察者进行注册、通知、注销

注意就是当我们在使用观察者模式的时候,当发生变化的时候,还是要主动调用notifyxxx()去通知观察者。 

  • DataSetObserver:观察者

方便区别,又可以理解为响应者。主要用来响应变化。

public abstract class DataSetObserver {
    public void onChanged() {
        // Do nothing
    }
    public void onInvalidated() {
        // Do nothing
    }
}

其中里面有两个方法:

1)onChanged():当数据或者需要观察的内容发生了改变,会调用这个方法来响应数据或者内容的变化。

2)onInvalidated():当所有数据都失效的时候,会调用该方法来处理数据失效。

  • DataSetObservable:被观察者

主要用来注册、通知、注销观察者,可以理解为观察者的管理者。

public class DataSetObservable extends Observable<DataSetObserver> {
    public void notifyChanged() {
        synchronized(mObservers) {
         
            for (int i = mObservers.size() - 1; i >= 0; i--) {
                mObservers.get(i).onChanged();
            }
        }
    }
    public void notifyInvalidated() {
        synchronized (mObservers) {
            for (int i = mObservers.size() - 1; i >= 0; i--) {
                mObservers.get(i).onInvalidated();
            }
        }
    }
}
public abstract class Observable<T> {

    protected final ArrayList<T> mObservers = new ArrayList<T>();

    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);
        }
    }
    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);
        }
    }
    public void unregisterAll() {
        synchronized(mObservers) {
            mObservers.clear();
        }
    }
}

我们可以看到所有的Observer被加入到一个ArrayList类型的mObservers集合中,在通知或注销Observer的时候,会按照先进后出的原则,通知或者注销所有的Observer。

其中里面的五个方法:

1)notifyChanged():通知所有已注册的观察者发生改变,并依次调用观察者的onChanged(),采用先进后出的原则;

2)notifyInvalidated():当数据失效或者不在使用的时候,依次调用观察者的onInvalidated(),采用先进后出的原则;

3)registerObserver():注册观察者,已经注册的会抛出异常,并有同步锁;

4)unregisterObserver():注销观察者,如果找不到该观察者抛出异常,并有同步锁;

5)unregisterAll():注销所有的观察者

实例讲解

我们来一个简单的例子来说明下Android观察者模式的用法。

1、定义一个类来继承DataSetObserver,用来实现当数据发生变化的时候,需要做出哪些相应的事件。

public class AdapterObserver extends DataSetObserver {
    String name;
    public AdapterObserver(String name) {
        this.name = name;
    }
    @Override
    public void onChanged() {
        System.out.println(name + " 观察者 on Changed");
    }
    @Override
    public void onInvalidated() {
        System.out.println(name + " 观察者 on Invalidated");
    }
   public String getName() {
        return name;
    }
}

2、定义被观察者,用来注册、通知、注销观察者,可以直接使用DataSetObservable,也可以去新建一个类去继承DataSetObservable,在对应的方法中增加一些自己的逻辑。

public class AdapterObservable extends DataSetObservable {
    String name = "";

    @Override
    public void registerObserver(DataSetObserver observer) {
        super.registerObserver(observer);
        setName(observer);
        System.out.println("注册观察者" + " " + name);
    }

    @Override
    public void notifyChanged() {
        super.notifyChanged();
        System.out.println("通知去change");
    }

    @Override
    public void notifyInvalidated() {
        super.notifyInvalidated();
        System.out.println("通知去Invalidated");
    }

    @Override
    public void unregisterObserver(DataSetObserver observer) {
        super.unregisterObserver(observer);
        setName(observer);
        System.out.println("注销观察者" + " " + name);
    }

    private void setName(DataSetObserver observer) {
        if (observer instanceof AdapterObserver) {
            name = ((AdapterObserver) observer).getName();
        }
    }
}

3、当需要进行观察某种变化的时候 ,首先要去注册观察者,然后在需要通知变化的时候,调用通知方法去通知观察者,最后在使用结束的时候,注意注销观察者

        DataSetObserver observer1 = new AdapterObserver("1");
        DataSetObserver observer2 = new AdapterObserver("2");
        AdapterObservable observable = new AdapterObservable();
        //注册
        observable.registerObserver(observer1);
        observable.registerObserver(observer2);
        //通知
        observable.notifyChanged();
        observable.notifyInvalidated();
        //注销
        observable.unregisterObserver(observer1);
        observable.unregisterObserver(observer2);

查看运行结果

    注册观察者 1
    注册观察者 2
    2 观察者 on Changed
    1 观察者 on Changed
    通知去change
    2 观察者 on Invalidated
    1 观察者 on Invalidated
    通知去Invalidated
    注销观察者 1
    注销观察者 2

在Android源码中的运用

 1、ListView的Adapter

1)被观察者的定义

在BaseAdapter中实例化了一个被观察者mDataSetObservable,然后BaseAdapter对外提供了registerDataSetObserver()、unregisterDataSetObserver()、notifyDataSetChanged()、notifyDataSetInvalidated()

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);
    }
    
    public void notifyDataSetChanged() {
        mDataSetObservable.notifyChanged();
    }

    public void notifyDataSetInvalidated() {
        mDataSetObservable.notifyInvalidated();
    }
//。。。。省略代码
}

2)观察者的定义

我们知道ListView最终继承的是AbsListView,所以最终注册、通知和注销是在AbsListView中实现的,当然Observer也是在AbsListView中,用来响应当数据源发生变化的时候,ListView来进行刷新UI的一个过程。

class AdapterDataSetObserver extends AdapterView<ListAdapter>.AdapterDataSetObserver {
        @Override
        public void onChanged() {
            super.onChanged();
//。。。。省略代码
        }
        @Override
        public void onInvalidated() {
            super.onInvalidated();
//。。。。省略代码
        }
    }
    class AdapterDataSetObserver extends DataSetObserver {
        @Override
        public void onChanged() {
//。。。。省略代码
        }
        @Override
        public void onInvalidated() {
//。。。。省略代码
        }
    }

3)在看看是什么时候进行注册、通知和注销的呢?

  • 注册

从代码中可以看到在onAttachedToWindow(),该View还没有执行onDraw()之前,注册观察者,同时mDataSetObserver == null来保证Observer只被注册一次。

   @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
//。。。。。省略代码 
//mDataSetObserver == null来保证该observer只被注册一次
        if (mAdapter != null && mDataSetObserver == null) {
            mDataSetObserver = new AdapterDataSetObserver();
            mAdapter.registerDataSetObserver(mDataSetObserver);
//。。。。。省略代码
        }
    }
  •  通知

一般就是在使用ListView的时候,当数据源发生变化的时候,开发人员主动调用adapter.notifyDataSetChanged()来通知该ListView中的被观察者要通知观察者onChanged()来 刷新UI了。

  • 注销
 @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
//。。。。省略代码
        if (mAdapter != null && mDataSetObserver != null) {
            mAdapter.unregisterDataSetObserver(mDataSetObserver);
            mDataSetObserver = null;
        }
//。。。。省略代码
 }

在onDetachedFromWindow()中,也就是基本上我们的Activity销毁的时候,该View从试图中移除的时候注销观察者。

2、TextWatcher

这个是EditText中对于文字编辑的状态的监听。EditText继承于TextView,最终代码实现在TextView。这个并没有利用Android提供的DataSetObserver和DataSetObservable,而是自定义的一套观察者模式。

1)被观察者的定义

整个TextView本身就是一个被观察者,可以看到里面关于对观察者的一些实现:

//存放所有的观察者   
 private ArrayList<TextWatcher> mListeners;
//注册观察者
 public void addTextChangedListener(TextWatcher watcher) {
        if (mListeners == null) {
            mListeners = new ArrayList<TextWatcher>();
        }

        mListeners.add(watcher);
    }
//注销观察者
    public void removeTextChangedListener(TextWatcher watcher) {
        if (mListeners != null) {
            int i = mListeners.indexOf(watcher);

            if (i >= 0) {
                mListeners.remove(i);
            }
        }
    }
//通知观察者
 private void sendBeforeTextChanged(CharSequence text, int start, int before, int after) {
        if (mListeners != null) {
            final ArrayList<TextWatcher> list = mListeners;
            final int count = list.size();
            for (int i = 0; i < count; i++) {
                list.get(i).beforeTextChanged(text, start, before, after);
            }
        }

        // 。。。。省略代码
}
//通知观察者 
void sendOnTextChanged(CharSequence text, int start, int before, int after) {
        if (mListeners != null) {
            final ArrayList<TextWatcher> list = mListeners;
            final int count = list.size();
            for (int i = 0; i < count; i++) {
                list.get(i).onTextChanged(text, start, before, after);
            }
        }
// 。。。。省略代码
    }
//通知观察者
    void sendAfterTextChanged(Editable text) {
        if (mListeners != null) {
            final ArrayList<TextWatcher> list = mListeners;
            final int count = list.size();
            for (int i = 0; i < count; i++) {
                list.get(i).afterTextChanged(text);
            }
        }
 // 。。。。省略代码
    }

区别于DataSetObservable,这里在注册的时候并没有对已经注册的会抛出异常,也没有同步锁。在进行通知的时候也不是先进后出的原则,就是先进先出的原则。

2)观察者的定义

就是自定义实现的TextWatcher

public class TextWatcherObserver extends TextWatcher {
    @Override
    public void beforeTextChanged(CharSequence s, int start,
                                  int count, int after){
   }
    @Override
    public void onTextChanged(CharSequence s, int start, int before, int count){
    }
    @Override
    public void afterTextChanged(Editable s){
    }
}

3)在看看是什么时候进行注册、通知和注销的呢?

  • 注册

注册就是在使用这个TextWatcher监听的时候,主动去注册

edittext.addTextChangedListener(watcher);
  • 通知

调用setText()

 public final void setText(char[] text, int start, int len) {
//。。。省略代码
        if (mText != null) {
            oldlen = mText.length();
        //通知
            sendBeforeTextChanged(mText, 0, oldlen, len);
        } else {
            sendBeforeTextChanged("", 0, 0, len);
        }
//。。。省略代码

        //通知
        sendOnTextChanged(text, 0, oldlen, textLength);
//。。。省略代码

        //通知
        if (needEditableForNotification) {
            sendAfterTextChanged((Editable) text);
        }
//。。。省略代码
}
  • 注销

当有注册的时候,需要主动去注销

edittext.removeTextChangedListener(watcher) ;

3、BroadcastReceiver

主要分析下动态注册中设计到观察者模式

1)被观察者的定义

整个ActivityManagerService就是一个被观察者,里面定义了对观察者的注册、通知、注销。

提供的registerReceiver()、unregisterReceiver()、sendBroadcast()。

而这里通过ActivityManagerProxy访问ActivityManagerService,采用的代理模式,来实现了跨进程之间访问。

从ContextImpl.registerReceiver,跟踪代码进入到registerReceiverInternal(),

可以看到最终注册是在ActivityManager.getService()返回的ActivityManagerService(ActivityManagerProxy为ActivityManagerService的代理类)中实现的。

  private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId,
            IntentFilter filter, String broadcastPermission,
            Handler scheduler, Context context, int flags) {
//。。。省略代码
        try {
            final Intent intent = ActivityManager.getService().registerReceiver(
                    mMainThread.getApplicationThread(), mBasePackageName, rd, filter,
                    broadcastPermission, userId, flags);
//。。。省略代码
            return intent;
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

进入到ActivityManagerService的registerReceiver()看一下

  public Intent registerReceiver(IApplicationThread caller, String callerPackage,
            IIntentReceiver receiver, IntentFilter filter, String permission, int userId,
            int flags) {
//。。。省略代码
    ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());
        if (rl == null) {
         rl = new ReceiverList(this, callerApp, callingPid, callingUid,
                        userId, receiver);
    }
//。。。省略代码
    mRegisteredReceivers.put(receiver.asBinder(), rl);
//。。。省略代码

}

这里的就是通过一系列的处理将注册的广播添加到下面的那个集合中。

    final HashMap<IBinder, ReceiverList> mRegisteredReceivers = new HashMap<>();

 同样unregisterReceiver(),也是从ContextImpl.unregisterReceiver()中也是进入到ActivityManagerService这里来实现注销通知,也就是从集合中取出之后,做一系列的处理。

 public void unregisterReceiver(IIntentReceiver receiver) {
        if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Unregister receiver: " + receiver);

//。。。。省略代码
            synchronized(this) {
                ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());
            }
//。。。。省略代码 
}

 最后就是通知sendBroadcast(),也是从ContextImpl.sendBroadcast()

    @Override
    public void sendBroadcast(Intent intent) {
 //。。。省略代码
            ActivityManager.getService().broadcastIntent(
                    mMainThread.getApplicationThread(), intent, resolvedType, null,
                    Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, false,
                    getUserId());
 //。。。省略代码
    }

对应的 ActivityManagerService的broadcastIntent()

2)观察者的定义

就是自定义的BroadcastReceiver

    private class BroadcastObserver extends BroadcastReceiver{
        @Override
        public void onReceive(Context context, Intent intent) {
            
        }
    }

3)在看看是什么时候进行注册、通知和注销的呢?

  • 注册

主动去调用registerReceiver()来注册观察者 

       context.registerReceiver(observer,filter);
  • 通知

在合适的时候,主动去调用sendBroadcast()来通知观察者 发生变化

     context.sendBroadcast(intent);

用完之后,要及时调用 unregisterReceiver()来注销观察者 

  • 注销
 context.unregisterReceiver(observer);

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值