1. 模式定義
定義對象間一種一對多的依賴關(guān)系,每當(dāng)一個對象改變狀態(tài)時,則所有依賴于它的對象都會
得到通知并被自動更新。
2. Android 源碼中的觀察者模式應(yīng)用
在 Android 的源碼中,我們接觸比較多的應(yīng)該是 RecyclerView 和 ListView 了,和其搭配使用的 Adapter,有 刷新列表的 notifyDataSetChanged() 方法,那么,該方法是怎樣刷新列表的呢?
首先我們要知道,觀察者模式被觀察者主要涉及三個操作:注冊(添加)觀察者、反注冊觀察者、通知觀察者更新。
那 RecyclerView 是什么時候執(zhí)行上述操作的呢?
RecyclerView.java
public void setAdapter(Adapter adapter) {
// bail out if layout is frozen
setLayoutFrozen(false);
setAdapterInternal(adapter, false, true);
requestLayout();
}
private void setAdapterInternal(Adapter adapter, boolean compatibleWithPrevious,
boolean removeAndRecycleViews) {
if (mAdapter != null) {
mAdapter.unregisterAdapterDataObserver(mObserver);
mAdapter.onDetachedFromRecyclerView(this);
}
if (!compatibleWithPrevious || removeAndRecycleViews) {
removeAndRecycleViews();
}
mAdapterHelper.reset();
final Adapter oldAdapter = mAdapter;
mAdapter = adapter;
if (adapter != null) {
// 1. 看到此處
adapter.registerAdapterDataObserver(mObserver);
adapter.onAttachedToRecyclerView(this);
}
if (mLayout != null) {
mLayout.onAdapterChanged(oldAdapter, mAdapter);
}
mRecycler.onAdapterChanged(oldAdapter, mAdapter, compatibleWithPrevious);
mState.mStructureChanged = true;
setDataSetChangedAfterLayout();
}
在上面的代碼 adapter.registerAdapterDataObserver(mObserver); 中,可以看到這就是注冊觀察者了,此方法屬于 RecyclerView 內(nèi)部類 Adapter
public abstract static class Adapter<VH extends ViewHolder> {
public void registerAdapterDataObserver(AdapterDataObserver observer) {
mObservable.registerObserver(observer);
}
public void unregisterAdapterDataObserver(AdapterDataObserver observer) {
mObservable.unregisterObserver(observer);
}
public final void notifyDataSetChanged() {
mObservable.notifyChanged();
}
}
當(dāng)我們更新 RecyclerView 數(shù)據(jù)源的時候,執(zhí)行了 adapter.notifyDataSetChanged(); 方法,那么此方法又做了什么工作呢?
RecyclerView 內(nèi)部類 Adapter
public final void notifyDataSetChanged() {
mObservable.notifyChanged();
}
RecyclerView 內(nèi)部類 AdapterDataObservable
static class AdapterDataObservable extends Observable<AdapterDataObserver> {
public void notifyChanged() {
// since onChanged() is implemented by the app, it could do anything, including
// removing itself from {@link mObservers} - and that could cause problems if
// an iterator is used on the ArrayList {@link mObservers}.
// to avoid such problems, just march thru the list in the reverse order.
for (int i = mObservers.size() - 1; i >= 0; i--) {
mObservers.get(i).onChanged();
}
}
}
RecyclerView 內(nèi)部類 AdapterDataObserver
public abstract static class AdapterDataObserver {
public void onChanged() {
// Do nothing
}
}
還記得上面我們注冊的方法入的參數(shù)嗎?就是 一個 AdapterDataObserver 對象
adapter.registerAdapterDataObserver(mObserver);
那么,這個 mObserver 是何物?
private final RecyclerViewDataObserver mObserver = new RecyclerViewDataObserver();
RecyclerView 內(nèi)部類 RecyclerViewDataObserver
private class RecyclerViewDataObserver extends AdapterDataObserver {
RecyclerViewDataObserver() {
}
@Override
public void onChanged() {
assertNotInLayoutOrScroll(null);
mState.mStructureChanged = true;
setDataSetChangedAfterLayout();
if (!mAdapterHelper.hasPendingUpdates()) {
requestLayout();
}
}
}
在此處,RecyclerView 會 requestLayout 等操作把列表給更新過來。
以上就是 RecyclerView 刷新列表的源碼分析了,使用了觀察者設(shè)計模式,對此,我們也可以使用該模式去處理一些有觀察和被觀察關(guān)系的場景。
3. 以公眾號推送為例介紹觀察者設(shè)計模式的精簡用法
觀察者:觀察者需要被 push
觀察者具有的操作接口
public interface IWXUser {
public void push(String article);
}
觀察者
public class WXUser implements IWXUser {
private String name;
public WXUser(String name) {
this.name = name;
}
@Override
public void push(String article) {
System.out.println(name + " 收到了一篇文章:" + article);
}
}
被觀察者:各種公眾號
public class WXPublicObservable {
// 所有訂閱的用戶(公眾號用戶)
public List<IWXUser> mWXUsers;
public WXPublicObservable(){
mWXUsers = new ArrayList<>();
}
/**
* 訂閱
*/
public void register(IWXUser wxUser){
mWXUsers.add(wxUser);
}
/**
* 取消訂閱
* @param wxUser
*/
public void unregister(IWXUser wxUser){
mWXUsers.remove(wxUser);
}
/**
* 更新文章
* @param article
*/
public void update(String article){
// 推送文章更新
for (IWXUser wxUser : mWXUsers) {
wxUser.push(article);
}
}
}
具體的被觀察者
public class WXxxxObservable extends WXPublicObservable {
private String article;
public String getArticle() {
return article;
}
public void setArticle(String article) {
this.article = article;
// 通知更新,推送給微信用戶
update(article);
}
}
3. 使用介紹
public class Client {
public static void main(String[] args){
// 微信公眾號 - 具體的被觀察者 - xxx
WXxxxObservable WXxxxObservable = new WXxxxObservable();
// 微信公眾號 - 具體的觀察者 vegen 和 小明同學(xué)
WXUser vegen = new WXUser("vegen");
WXUser xiaoming = new WXUser("小明同學(xué)");
// 微信公眾號 - 用戶訂閱公眾號
WXxxxObservable.register(vegen);
WXxxxObservable.register(xiaoming);
// 微信公眾號 - 推送文章
WXxxxObservable.setArticle("我是文章巴拉巴拉1");
// 微信公眾號 - 用戶取消訂閱公眾號
WXxxxObservable.unregister(vegen);
// 微信公眾號 - 推送文章
WXxxxObservable.setArticle("我是文章巴拉巴拉2");
}
}
vegen 和 小明同學(xué) 都能收到 文章巴拉巴拉1 的提示,vegen 后面取消了訂閱,就只有 小明同學(xué)收到了 文章巴拉巴拉2 的提示。