設計模式(五)RecyclerView中的觀察者模式

1、基本概念

一、定義:

定義對象間的一種一對多的依賴關係,當一個對象的狀態發生改變時,全部依賴於它的對象都能獲得通知並被自動更新。 例如:天氣預報服務,一旦你訂閱該服務,,天天一旦有天氣信息更新,它就會及時向你發送最新的天氣信息。java

二、使用場景

  • 關聯行爲場景
  • 時間多級觸發場景

三、結構圖

  • Subject:抽象被觀察者,會將全部觀察者對象保存到一個集合中,提供方法來添加和刪除觀察者。
  • ConcreteSubject:具體被觀察者,如自身發生改變,給全部註冊過的觀察者發通知。
  • Observer:抽象觀察者,定義更新接口,若是接受到被觀察者的通知後,自身進行更新。
  • ConcreteObserver:具體觀察者,實現抽象觀察者鎖定義的更新接口

2、相關實例

定義天氣做爲被觀察者,若是天氣更新,觀察者進行數據更新bash

一、Subject

/**
 * 被觀察者接口
 */
public interface Subject {
    //註冊觀察者
    void registObserver(Observer observer);
    //取消註冊
    void unRegistObserver(Observer observer);
    //通知觀察者
    void notifiObservers();
}
複製代碼

二、Observer

/**
 * 觀察者接口
 */
public interface Observer<T> {
    //數據更新
    void update(T t);
}
複製代碼

三、ConcreteSubject

public class Weather implements Subject {
    private Vector<Observer> mObservers = new Vector<>();
    public int mTemp;
    @Override
    public void registObserver(Observer observer) {
        this.mObservers.add(observer);
    }

    @Override
    public void unRegistObserver(Observer observer) {
        this.mObservers.remove(observer);
    }

    @Override
    public void notifiObservers() {
        for (Observer observer : mObservers) {
            observer.update(this);
        }
    }

    /**
     * 溫度更新後,通知被觀察者
     * @param temp
     */
    public void updateTemp(int temp){
	    this.mTemp = temp;
        notifiObservers();
    }
}
複製代碼

四、ConcreteObserver

public class Forecast implements Observer<Weather>{
    @Override
    public void update(Weather weather) {
        System.out.println("溫度調整爲:"+weather.mTemp);
    }
}
複製代碼

五、使用:

public class ObserverTest {
    public static void main(String[] args){
        Weather weather = new Weather();
        Forecast forecast = new Forecast();
        //註冊觀察者
        weather.registObserver(forecast);
        //被觀察者數據有更新
        weather.updateTemp(15);
    }
}
複製代碼

當天氣有溫度更新時,天氣預報會收到相應的通知,並進行對應的更新。ide

3、java.util.Observable源碼解析

java中提供了Observerable和Observer相關實現類ui

一、java.util.Observable 被觀察者

public class Observable {
    private boolean changed = false;
    private final ArrayList<Observer> observers;

    public Observable() {
        observers = new ArrayList<>();
    }

    //添加觀察者
    public synchronized void addObserver(Observer o) {
        if (o == null)
            throw new NullPointerException();
        if (!observers.contains(o)) {
            observers.add(o);
        }
    }

    //刪除觀察者
    public synchronized void deleteObserver(Observer o) {
        observers.remove(o);
    }

    //通知觀察者
    public void notifyObservers() {
        notifyObservers(null);
    }

    public void notifyObservers(Object arg) {
        Observer[] arrLocal;
        synchronized (this) {
            //當changed爲true的時候才通知觀察者
            if (!hasChanged())
                return;
            arrLocal = observers.toArray(new Observer[observers.size()]);
            clearChanged();
        }
        for (int i = arrLocal.length - 1; i >= 0; i--)
            arrLocal[i].update(this, arg);
    }

    public synchronized void deleteObservers() {
        observers.clear();
    }

    //將changed設爲true
    protected synchronized void setChanged() {
        changed = true;
    }

    //清除狀態
    protected synchronized void clearChanged() {
        changed = false;
    }

    //查詢狀態
    public synchronized boolean hasChanged() {
        return changed;
    }

    public synchronized int countObservers() {
        return observers.size();
    }
}
複製代碼

二、java.util.Observer

public interface Observer {    
    void update(Observable o, Object arg);
}
複製代碼

觀察者接口,定義了更新的方法this

三、實例調用:

(1)被觀察者spa

public class Weather extends Observable {
    public int mTemp;

    /**
     * 溫度更新後,通知被觀察者
     * @param temp
     */
    public void updateTemp(int temp){
        this.mTemp = temp;
        setChanged();
        notifyObservers(this);
    }
}
複製代碼

(2)觀察者code

public class Forecast implements Observer {
    @Override
    public void update(Observable o, Object arg) {
        if (arg instanceof Weather) {
            System.out.println("溫度調整爲:"+((Weather) arg).mTemp);
        }
    }
}
複製代碼

(3)使用cdn

public class ObserverTest {
    public static void main(String[] args) {
        Weather weather = new Weather();
        Forecast forecast = new Forecast();
        weather.addObserver(forecast);
        weather.updateTemp(20);
    }
}
複製代碼

觀察者接受到了通知並進行了更新server

4、RecycleView中的觀察者

一、Adapter

public static abstract class Adapter<VH extends ViewHolder> {
  //建立一個被觀察者,用來添加、刪除、通知觀察者
  private final AdapterDataObservable mObservable = new AdapterDataObservable();

  ......
  /**
   * 註冊觀察者
   * @param observer
   */
  public void registerAdapterDataObserver(AdapterDataObserver observer) {
    mObservable.registerObserver(observer);
  }

  /**
   * 取消註冊觀察者
   * @param observer
   */
  public void unregisterAdapterDataObserver(AdapterDataObserver observer) {
    mObservable.unregisterObserver(observer);
  }

  /**
   * 通知已註冊的觀察者更新數據
   */
  public final void notifyDataSetChanged() {
    mObservable.notifyChanged();
  }

  /**
   * 通知已註冊的觀察者某個索引的數據發生改變
   */
  public final void notifyItemChanged(int position) {
    mObservable.notifyItemRangeChanged(position, 1);
  }
  ......
}
複製代碼
  • 能夠進行註冊和取消註冊觀察者,內部實如今AdapterDataObservable中
  • 在adapter數據更新時,通知觀察者數據已發生改變

二、AdapterDataObservable

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();
    }
  }

  /**
   * 遍歷觀察者,調用其onItemRangeChanged方法
   * @param positionStart
   * @param itemCount
   * @param payload
   */
  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做爲一個被觀察者,繼承了Observable,在數據發生改變時,遍歷通知觀察者調用其回調方法。對象

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();
    }
  }
}
複製代碼

三、觀察者AdapterDataObserver

public static abstract class AdapterDataObserver {
  public void onChanged() {
  }

  public void onItemRangeChanged(int positionStart, int itemCount) {

  }

  public void onItemRangeChanged(int positionStart, int itemCount, Object payload) {
    onItemRangeChanged(positionStart, itemCount);
  }

  public void onItemRangeInserted(int positionStart, int itemCount) {
   
  }

  public void onItemRangeRemoved(int positionStart, int itemCount) {
   
  }

  public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {

  }
}
複製代碼

做爲觀察者,定義一些回調方法,在被觀察者發生改變時會被調用

四、觀察者註冊

經過Adapter的registerAdapterDataObserver進行註冊

(1)RecyclerView的setAdapter

#RecyclerView
public void setAdapter(Adapter adapter) {
    // bail out if layout is frozen
  setLayoutFrozen(false);
  setAdapterInternal(adapter, false, true);
  requestLayout();
}

private void setAdapterInternal(RecyclerView.Adapter adapter, boolean compatibleWithPrevious,
    boolean removeAndRecycleViews) {
  //先經過以前的adapter將觀察者取消註冊
  if (mAdapter != null) {
    mAdapter.unregisterAdapterDataObserver(mObserver);
    mAdapter.onDetachedFromRecyclerView(this);
  }
  if (!compatibleWithPrevious || removeAndRecycleViews) {
    removeAndRecycleViews();
  }
  mAdapterHelper.reset();
  final RecyclerView.Adapter oldAdapter = mAdapter;
  mAdapter = adapter;
  //註冊新的觀察者
  if (adapter != null) {
    adapter.registerAdapterDataObserver(mObserver);
    adapter.onAttachedToRecyclerView(this);
  }
  ......
}
複製代碼
相關文章
相關標籤/搜索