设计模式(六)RecyclerView中的观察者模式

1,080 阅读4分钟

一、基本概念

1、定义:

定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都能得到通知并被自动更新。 例如:天气预报服务,一旦你订阅该服务,,每天一旦有天气信息更新,它就会及时向你发送最新的天气信息。

2、使用场景

  • 关联行为场景
  • 时间多级触发场景

3、结构图

  • Subject:抽象被观察者,会将所有观察者对象保存到一个集合中,提供方法来添加和删除观察者。
  • ConcreteSubject:具体被观察者,如自身发生改变,给所有注册过的观察者发通知。
  • Observer:抽象观察者,定义更新接口,如果接受到被观察者的通知后,自身进行更新。
  • ConcreteObserver:具体观察者,实现抽象观察者锁定义的更新接口

二、相关实例

定义天气作为被观察者,如果天气更新,观察者进行数据更新

1、Subject

/**
 * 被观察者接口
 */
public interface Subject {
    //注册观察者
    void registObserver(Observer observer);
    //取消注册
    void unRegistObserver(Observer observer);
    //通知观察者
    void notifiObservers();
}

2、Observer

/**
 * 观察者接口
 */
public interface Observer<T> {
    //数据更新
    void update(T t);
}

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

4、ConcreteObserver

public class Forecast implements Observer<Weather>{
    @Override
    public void update(Weather weather) {
        System.out.println("温度调整为:"+weather.mTemp);
    }
}

5、使用:

public class ObserverTest {
    public static void main(String[] args){
        Weather weather = new Weather();
        Forecast forecast = new Forecast();
        //注册观察者
        weather.registObserver(forecast);
        //被观察者数据有更新
        weather.updateTemp(15);
    }
}

当天气有温度更新时,天气预报会收到相应的通知,并进行对应的更新。

三、java.util.Observable源码解析

java中提供了Observerable和Observer相关实现类

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

2、java.util.Observer

public interface Observer {    
    void update(Observable o, Object arg);
}

观察者接口,定义了更新的方法

3、实例调用:

(1)被观察者

public class Weather extends Observable {
    public int mTemp;

    /**
     * 温度更新后,通知被观察者
     * @param temp
     */
    public void updateTemp(int temp){
        this.mTemp = temp;
        setChanged();
        notifyObservers(this);
    }
}

(2)观察者

public class Forecast implements Observer {
    @Override
    public void update(Observable o, Object arg) {
        if (arg instanceof Weather) {
            System.out.println("温度调整为:"+((Weather) arg).mTemp);
        }
    }
}

(3)使用

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

观察者接受到了通知并进行了更新

四、RecycleView中的观察者

1、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数据更新时,通知观察者数据已发生改变

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

3、观察者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) {

  }
}

作为观察者,定义一些回调方法,在被观察者发生改变时会被调用

4、观察者注册

通过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);
  }
  ......
}

汇总:设计模式总结