從RecyclerView的源碼瞭解觀察者模式

觀察者模式

定義對象以前一種一對多的依賴關係,使得當一個對象改變狀態,全部依賴這個對象的對象都會獲得通知而且自動更新。java

使用場景

  • 關聯行爲場景。關聯行爲是可拆分的,不是「組合」關係
  • 事件多級觸發場景
  • 跨系統的消息交互場景。好比消息隊列事件總線的處理機制

結構和UML圖

觀察者模式UML.jpg

  • Subject-抽象主題: 就是被觀察者(Observable)角色,抽象主題角色把全部的觀察者的引用保存在一個集合中,每一個主題均可以有任意數量的觀察者,抽象主題提供一個接口麼能夠添加/刪除觀察者對象。
  • ConcreteSubject-具體主題: 又名具體被觀察者,該以爲將有關組狀態保存進具體的觀察者對象,在具體主題的內部狀態發生改變時,給全部註冊過的觀察者發送通知。
  • Observer-抽象觀察者; 觀察者的抽象類,定義了一個更新接口,使得在獲得主題的更改通知時來更改本身。
  • ConcreteSubject-具體的觀察者; 實現了抽象觀察者角色所定義的更新接口,以便在主題的狀態改變時更新自身的狀態。

簡單示例

咱們平時若是訂閱了某個平臺的博客,在有新的博客時會經過郵件等方式通知咱們訂閱者。這裏我就以這個寫一個簡單的觀察者模式的示例 抽象主題:設計模式

//抽象主題角色,Subject:被觀察者
public abstract class Blog {
	protected final ArrayList<User> mObservers = new ArrayList();
	
	public void addUser(User user){
		mObservers.add(user);
	}
	
	public void removeUser(User user){
		mObservers.remove(user);
	}
	
	public void removeAll(){
		mObservers.clear();
	}
}

複製代碼

具體主題:
markdown

// 具體主題角色,ConcreteSubject:具體被觀察者
public class ConcreteBlog extends Blog{

	public ConcreteBlog() {
		// TODO Auto-generated constructor stub
	}
	
	public void notifyChanged(String str){
		for(int i=mObservers.size()-1;i>=0;i--){
			mObservers.get(i).update(str);
		}
	}

}

複製代碼

抽象觀察者:
app

// 抽象觀察者角色
public abstract class User {

	public void update(String str) {
	}

}

複製代碼

具體的觀察者:ide

public class ConcreteUser extends User {

	@Override
	public void update(String str) {
		System.out.println(str);
	}
}
複製代碼

使用:佈局

public class Client {

	public Client() {
		// TODO Auto-generated constructor stub
	}
	
	public static void main(String[] args) {
		// 建立被觀察者
		ConcreteBlog blog=new ConcreteBlog();
		// 建立觀察者
		ConcreteUser user1=new ConcreteUser();
		ConcreteUser user2=new ConcreteUser();
		ConcreteUser user3=new ConcreteUser();
		// 將觀察者註冊到可觀察對象的觀察者列表中
		blog.addUser(user1);
		blog.addUser(user2);
		blog.addUser(user3);
		
		blog.notifyChanged("發佈博客了,快來看啊!");
	}

}}
複製代碼

以上內容來摘抄自《Android源碼設計模式解析與實戰》this

RecyclerView源碼中的觀察者模式

在使用RecyclerView的時候,咱們在每次更新了RecyclerView的數據後一般調用notifyDataSetChanged()方法來更新咱們的視圖。那麼咱們就從這裏開始,到源碼看看RecyclerView的觀察者模式是怎麼實現的spa

public static abstract class Adapter<VH extends ViewHolder> {
        // 定義觀察者
        private final AdapterDataObservable mObservable = new AdapterDataObservable();
        private boolean mHasStableIds = false;
        public abstract VH onCreateViewHolder(ViewGroup parent, int viewType);
        // 省略...
        public void registerAdapterDataObserver(AdapterDataObserver observer) {
            mObservable.registerObserver(observer);
        }
        public void unregisterAdapterDataObserver(AdapterDataObserver observer) {
            mObservable.unregisterObserver(observer);
        }
        // 通知全部觀察者
        public final void notifyDataSetChanged() {
            mObservable.notifyChanged();
        }

複製代碼

由上可知,其實**RecyclerView.Adapter本質就是觀察者模式**,接着下一步咱們跟進到notifyDataSetChanged()方法來看看設計

static class AdapterDataObservable extends Observable<AdapterDataObserver> {
        public boolean hasObservers() {
            return !mObservers.isEmpty();
        }
        // 調用每個觀察者的onChanged()方法來通知他們被觀察者發生了變化
        public void notifyChanged() {
            for (int i = mObservers.size() - 1; i >= 0; i--) {
                mObservers.get(i).onChanged();
            }
        }

        public void notifyItemRangeChanged(int positionStart, int itemCount) {
            notifyItemRangeChanged(positionStart, itemCount, null);
        }

        public void notifyItemRangeChanged(int positionStart, int itemCount, Object payload) {
            for (int i = mObservers.size() - 1; i >= 0; i--) {
                mObservers.get(i).onItemRangeChanged(positionStart, itemCount, payload);
            }
        }
       // 省略...
複製代碼

這樣一看,原來就是在AdapterDataObservable.notifyChanged()方法中來遍歷全部的觀察者,調用他們的onChange()方法來通知的。其中notifyItemRangeChanged()也是經過同樣的模式去通知觀察者的。code

這樣下來,咱們知道了被觀察者(Observable)是怎麼實現的,如今咱們來找找看觀察者(Observer)是從哪兒來的呢? 回想一下,平時咱們RecyclerView關聯數據的時候都是經過調用setAdapter()方法實現的,那咱們進去看看

public void setAdapter(Adapter adapter) {
        // bail out if layout is frozen
        setLayoutFrozen(false);
        setAdapterInternal(adapter, false, true);
        requestLayout();
    }
複製代碼

咦?該方法把adapter傳進了setAdapterInternal()方法,咱們再跟進去看看。其實看到其後會調用requestLayout()方法來重繪View咱們就知道觀察者的註冊操做確定是在上面方法中完成。

// 定義在RecyclerView中,RecyclerViewDataObserver繼承與AdapterDataObserver
private final RecyclerViewDataObserver mObserver = new RecyclerViewDataObserver();

private void setAdapterInternal(Adapter adapter, boolean compatibleWithPrevious, boolean removeAndRecycleViews) {
        // 若是當前已經存在一個adapter了,就先註銷這個adapter對象的觀察者
        if (mAdapter != null) {
            mAdapter.unregisterAdapterDataObserver(mObserver);
            mAdapter.onDetachedFromRecyclerView(this);
        }
        if (!compatibleWithPrevious || removeAndRecycleViews) {
            removeAndRecycleViews();
        }
        mAdapterHelper.reset();
        final Adapter oldAdapter = mAdapter;
        mAdapter = adapter;
        if (adapter != null) {
            // 將觀察者註冊到Adapter中,實質是註冊到AdapterDataObservable中
            adapter.registerAdapterDataObserver(mObserver);
            adapter.onAttachedToRecyclerView(this);
        }
        if (mLayout != null) {
            mLayout.onAdapterChanged(oldAdapter, mAdapter);
        }
        // 數據更新操做
        mRecycler.onAdapterChanged(oldAdapter, mAdapter, compatibleWithPrevious);
        mState.mStructureChanged = true;
        // 將以前的全部已知的itemveiw設置invalid(ViewHolder標誌位FLAG_UPDATE | FLAG_INVALID)
        markKnownViewsInvalid();
    }
複製代碼

經過以上的代碼咱們知道,在設置setAdapter的時候會構建一個RecyclerViewDataObserver,也就是觀察者,而後將它註冊到被觀察者-AdapterDataObservable中。 咱們找到了被觀察者是怎麼和觀察者關聯的,可是具體RecyclerViewDataObserver是什麼東西呢?內部是怎麼閃現的呢?咱們繼續研究研究,上面代碼中我提到RecyclerViewDataObserver繼承與AdapterDataObserver,那咱們先來看看他的父類

public static abstract class AdapterDataObserver {
        public void onChanged() {
            // Do nothing
        }

        public void onItemRangeChanged(int positionStart, int itemCount) {
            // do nothing
        }

        public void onItemRangeChanged(int positionStart, int itemCount, Object payload) {
            // fallback to onItemRangeChanged(positionStart, itemCount) if app
            // does not override this method.
            onItemRangeChanged(positionStart, itemCount);
        }

        public void onItemRangeInserted(int positionStart, int itemCount) {
            // do nothing
        }

        public void onItemRangeRemoved(int positionStart, int itemCount) {
            // do nothing
        }

        public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
            // do nothing
        }
    }
複製代碼

基本父類都是空方法,沒有具體的實現。咱們在來看看RecyclerViewDataObserver是如何重寫父類的onChanged()方法的

private class RecyclerViewDataObserver extends AdapterDataObserver {
        RecyclerViewDataObserver() {
        }

        @Override
        public void onChanged() {
            assertNotInLayoutOrScroll(null);
            mState.mStructureChanged = true;
            //
            setDataSetChangedAfterLayout();
            if (!mAdapterHelper.hasPendingUpdates()) {
                //從新佈局
                requestLayout();
            }
        }
        ......//省略 
}
複製代碼

目前就到此爲止吧,總結一下,當RecyclerView的數據發生變化時,調用AdapternotifyDataSetChanged()方法,這個方法又會調用AdapterDataObservablenotifyChanged()方法。這個方法又會調用全部觀察者的onChanged()方法,在onChanged方法裏對RecyclerView進行從新佈局是的RecyclerView刷新界面。一個完整的觀察者模式就出來了。

總結

在建立Adapter的時候構建了一個RecyclerViewDataObserver,而且在setAdapter()的時候將其註冊進了Adapter(本質是註冊到AdapterDataObservable)。在咱們調用notifyDataSetChanged()方法的時候,其實就是調用了AdapterDataObservablenotifyChanged()方法,該方法會遍歷全部觀察者的onChanged()方法,該方法會調用RecyclerView從新佈局。

相關文章
相關標籤/搜索