定義對象以前一種一對多的依賴關係,使得當一個對象改變狀態,全部依賴這個對象的對象都會獲得通知而且自動更新。java
咱們平時若是訂閱了某個平臺的博客,在有新的博客時會經過郵件等方式通知咱們訂閱者。這裏我就以這個寫一個簡單的觀察者模式的示例 抽象主題:設計模式
//抽象主題角色,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
的數據後一般調用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();
}
複製代碼
經過以上的代碼咱們知道,在設置setAdapte
r的時候會構建一個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
的數據發生變化時,調用Adapter
的notifyDataSetChanged()
方法,這個方法又會調用AdapterDataObservable
的notifyChanged
()方法。這個方法又會調用全部觀察者的onChanged()
方法,在onChanged
方法裏對RecyclerView
進行從新佈局是的RecyclerView
刷新界面。一個完整的觀察者模式就出來了。
在建立Adapter
的時候構建了一個RecyclerViewDataObserver
,而且在setAdapter()
的時候將其註冊進了Adapter
(本質是註冊到AdapterDataObservable
)。在咱們調用notifyDataSetChanged()
方法的時候,其實就是調用了AdapterDataObservable
的notifyChanged()
方法,該方法會遍歷全部觀察者的onChanged()
方法,該方法會調用RecyclerView
從新佈局。