Quantcast
Channel: CSDN博客移动开发推荐文章
Viewing all articles
Browse latest Browse all 5930

设计模式-观察者模式

$
0
0

1.观察者模式的定义及使用场景

观察者模式是一个使用率非常高的模式,它最常用的地方是GUI系统,订阅-发布系统。因为这个模式的一个重要作用就是解耦,将被观察者和观察者解耦,使得它们之间的依赖性更小。

定义:

定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所以依赖于它的对象都会得到通知并被自动更新

使用场景:

  • 关联行为场景,需要注意的是,关联行为时可拆分的,而不是“组合”关系;
  • 事件多级触发场景
  • 跨系统的消息交换场景,如消息队列、事件总线的处理机制

这里写图片描述

2. 观察者模式的优缺点

2.1优点

  • 观察者和被观察者之间是抽象解耦,应对业务变化
  • 增强系统灵活性、可扩展性

2.2缺点

在应用观察者模式时需要考虑一下开发效率和运行效率问题,程序中包括一个被观察者、多个观察者、开发和调试等内容会比较复杂,而且在Java中消息的通知默认是顺序执行,一个观察者卡顿,会影响整体的执行效率,在这种情况下,一般考虑采用异步的方式

3. 观察者模式的实现方式

public interface Observer {
    //更新方法
    public void  update();
}
public class ConcreteObsever implements Observer {
    @Override
    public void update() {
        System.out.println("接收到信息,并进行处理!");
    }
}
public abstract class Subject {
    //定义一个观察者数组
    private List<Observer> observers = new ArrayList<>();

    //增加一个观察者
    public void addObserver(Observer o) {
        this.observers.add(o);
    }

    //删除一个观察者
    public void removeObserver(Observer o) {
        this.observers.remove(o);
    }

    //通知所有观察者
    public void notifyObservers() {
        for (Observer o : this.observers) {
            o.update();
        }
    }
}
public class ConcreteSubject extends Subject {

    //具体的业务
    public void doSomeThing() {
        super.notifyObservers();
    }
}
public class Test {

    public static void main(String args[]) {
      //创建一个被观察者
        ConcreteSubject subject=new ConcreteSubject();
        Observer obs=new ConcreteObsever();
        subject.addObserver(obs);
        subject.doSomeThing();
    }
}

4. 观察者模式在Android中的实际应用

RecycleView是Android中最重要的控件之一,而RecycleView最重要的一个功能就是Adapter。通过我们往RecycleView添加数据后,都会调用Adapter的notifyDataSetChanged()方法,这是为什么?
首先我们看下Adapter的实现,他是RecycleView的一个内部类。

  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 abstract void onBindViewHolder(VH holder, int position);

  public void onBindViewHolder(VH holder, int position, List<Object> payloads) {
  onBindViewHolder(holder, position);
  }

  public final VH createViewHolder(ViewGroup parent, int viewType) {
  TraceCompat.beginSection(TRACE_CREATE_VIEW_TAG);
  final VH holder = onCreateViewHolder(parent, viewType);
  holder.mItemViewType = viewType;
  TraceCompat.endSection();
  return holder;
  }

  public final void bindViewHolder(VH holder, int position) {
  holder.mPosition = position;
  if (hasStableIds()) {
  holder.mItemId = getItemId(position);
  }
  holder.setFlags(ViewHolder.FLAG_BOUND,
  ViewHolder.FLAG_BOUND | ViewHolder.FLAG_UPDATE | ViewHolder.FLAG_INVALID
  | ViewHolder.FLAG_ADAPTER_POSITION_UNKNOWN);
  TraceCompat.beginSection(TRACE_BIND_VIEW_TAG);
  onBindViewHolder(holder, position, holder.getUnmodifiedPayloads());
  holder.clearPayload();
  TraceCompat.endSection();
  }

  public int getItemViewType(int position) {
  return 0;
  }

  public void setHasStableIds(boolean hasStableIds) {
  if (hasObservers()) {
  throw new IllegalStateException("Cannot change whether this adapter has " +
  "stable IDs while the adapter has registered observers.");
  }
  mHasStableIds = hasStableIds;
  }

  public long getItemId(int position) {
  return NO_ID;
  }

  public abstract int getItemCount();

  public final boolean hasStableIds() {
  return mHasStableIds;
  }

  public void onViewRecycled(VH holder) {
  }

  public boolean onFailedToRecycleView(VH holder) {
  return false;
  }

  public void onViewAttachedToWindow(VH holder) {
  }

  public void onViewDetachedFromWindow(VH holder) {
  }

  public final boolean hasObservers() {
  return mObservable.hasObservers();
  }

  public void registerAdapterDataObserver(AdapterDataObserver observer) {
  mObservable.registerObserver(observer);
  }

  public void unregisterAdapterDataObserver(AdapterDataObserver observer) {
  mObservable.unregisterObserver(observer);
  }

  public void onAttachedToRecyclerView(RecyclerView recyclerView) {
  }

  public void onDetachedFromRecyclerView(RecyclerView recyclerView) {
  }

  public final void notifyDataSetChanged() {
  mObservable.notifyChanged();
  }

  public final void notifyItemChanged(int position) {
  mObservable.notifyItemRangeChanged(position, 1);
  }

  public final void notifyItemChanged(int position, Object payload) {
  mObservable.notifyItemRangeChanged(position, 1, payload);
  }

  public final void notifyItemRangeChanged(int positionStart, int itemCount) {
  mObservable.notifyItemRangeChanged(positionStart, itemCount);
  }

  public final void notifyItemRangeChanged(int positionStart, int itemCount, Object payload) {
  mObservable.notifyItemRangeChanged(positionStart, itemCount, payload);
  }

  public final void notifyItemInserted(int position) {
  mObservable.notifyItemRangeInserted(position, 1);
  }

  public final void notifyItemMoved(int fromPosition, int toPosition) {
  mObservable.notifyItemMoved(fromPosition, toPosition);
  }

  public final void notifyItemRangeInserted(int positionStart, int itemCount) {
  mObservable.notifyItemRangeInserted(positionStart, itemCount);
  }

  public final void notifyItemRemoved(int position) {
  mObservable.notifyItemRangeRemoved(position, 1);
  }

  public final void notifyItemRangeRemoved(int positionStart, int itemCount) {
  mObservable.notifyItemRangeRemoved(positionStart, itemCount);
  }
  }

我们可以看到notifyDataSetChange()中调用了mObservable.notifyChange()。继续看AdapterDataObservable类

  static class AdapterDataObservable extends Observable<AdapterDataObserver> {
  public boolean hasObservers() {
  return !mObservers.isEmpty();
  }

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

  public void notifyItemRangeInserted(int positionStart, int itemCount) {

  for (int i = mObservers.size() - 1; i >= 0; i--) {
  mObservers.get(i).onItemRangeInserted(positionStart, itemCount);
  }
  }

  public void notifyItemRangeRemoved(int positionStart, int itemCount) {

  for (int i = mObservers.size() - 1; i >= 0; i--) {
  mObservers.get(i).onItemRangeRemoved(positionStart, itemCount);
  }
  }

  public void notifyItemMoved(int fromPosition, int toPosition) {
  for (int i = mObservers.size() - 1; i >= 0; i--) {
  mObservers.get(i).onItemRangeMoved(fromPosition, toPosition, 1);
  }
  }
  }

Observable是一个被观察者:

public abstract class Observable<T> {
  /**
  * The list of observers. An observer can be in the list at most
  * once and will never be null.
  */
  protected final ArrayList<T> mObservers = new ArrayList<T>();

  /**
  * Adds an observer to the list. The observer cannot be null and it must not already
  * be registered.
  * @param observer the observer to register
  * @throws IllegalArgumentException the observer is null
  * @throws IllegalStateException the observer is already registered
  */
  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);
  }
  }

  /**
  * Removes a previously registered observer. The observer must not be null and it
  * must already have been registered.
  * @param observer the observer to unregister
  * @throws IllegalArgumentException the observer is null
  * @throws IllegalStateException the observer is not yet registered
  */
  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);
  }
  }

  /**
  * Remove all registered observers.
  */
  public void unregisterAll() {
  synchronized(mObservers) {
  mObservers.clear();
  }
  }
}

AdapterDataObserver 的派生类RecyclerViewDataObserver: mObserver是RecycleView的一个变量

 private final RecyclerViewDataObserver mObserver = new RecyclerViewDataObserver();
  private class RecyclerViewDataObserver extends AdapterDataObserver {
  @Override
  public void onChanged() {
  assertNotInLayoutOrScroll(null);
  if (mAdapter.hasStableIds()) {
  // TODO Determine what actually changed.
  // This is more important to implement now since this callback will disable all
  // animations because we cannot rely on positions.
  mState.mStructureChanged = true;
  setDataSetChangedAfterLayout();
  } else {
  mState.mStructureChanged = true;
  setDataSetChangedAfterLayout();
  }
  if (!mAdapterHelper.hasPendingUpdates()) {
  requestLayout();
  }
  }

  @Override
  public void onItemRangeChanged(int positionStart, int itemCount, Object payload) {
  assertNotInLayoutOrScroll(null);
  if (mAdapterHelper.onItemRangeChanged(positionStart, itemCount, payload)) {
  triggerUpdateProcessor();
  }
  }

  @Override
  public void onItemRangeInserted(int positionStart, int itemCount) {
  assertNotInLayoutOrScroll(null);
  if (mAdapterHelper.onItemRangeInserted(positionStart, itemCount)) {
  triggerUpdateProcessor();
  }
  }

  @Override
  public void onItemRangeRemoved(int positionStart, int itemCount) {
  assertNotInLayoutOrScroll(null);
  if (mAdapterHelper.onItemRangeRemoved(positionStart, itemCount)) {
  triggerUpdateProcessor();
  }
  }

  @Override
  public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
  assertNotInLayoutOrScroll(null);
  if (mAdapterHelper.onItemRangeMoved(fromPosition, toPosition, itemCount)) {
  triggerUpdateProcessor();
  }
  }

  void triggerUpdateProcessor() {
  if (mPostUpdatesOnAnimation && mHasFixedSize && mIsAttached) {
  ViewCompat.postOnAnimation(RecyclerView.this, mUpdateChildViewsRunnable);
  } else {
  mAdapterUpdateDuringMeasure = true;
  requestLayout();
  }
  }
  }

RecycleView的setAdapter方法,可以看到里面调用了unregisterAdapterDataObserver及registerAdapterDataObserver方法进行取消注册及注册。

 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) {
  // end all running animations
  if (mItemAnimator != null) {
  mItemAnimator.endAnimations();
  }
  // Since animations are ended, mLayout.children should be equal to
  // recyclerView.children. This may not be true if item animator's end does not work as
  // expected. (e.g. not release children instantly). It is safer to use mLayout's child
  // count.
  if (mLayout != null) {
  mLayout.removeAndRecycleAllViews(mRecycler);
  mLayout.removeAndRecycleScrapInt(mRecycler);
  }
  // we should clear it here before adapters are swapped to ensure correct callbacks.
  mRecycler.clear();
  }
  mAdapterHelper.reset();
  final Adapter oldAdapter = mAdapter;
  mAdapter = adapter;
  if (adapter != null) {
  adapter.registerAdapterDataObserver(mObserver);
  adapter.onAttachedToRecyclerView(this);
  }
  if (mLayout != null) {
  mLayout.onAdapterChanged(oldAdapter, mAdapter);
  }
  mRecycler.onAdapterChanged(oldAdapter, mAdapter, compatibleWithPrevious);
  mState.mStructureChanged = true;
  markKnownViewsInvalid();
  }

到这里我们知道,setAdapter()方法会进行观察者的注册,当RecycleView的数据发送变化的时,调用了Adapter的notifyDataSetChange(),这个函数又会调用 AdapterDataObservable的notifyChanged();该函数会遍历所有的观察者的onChange函数,在 RecyclerViewDataObserver的onChange()函数中会获取Adapter中数据集的新数量,然后调用RecycleView的requestLayout()方法重新进行布局,更新用户的界面。这就是一个观察者模式!

作者:junbin1011 发表于2017/2/27 11:00:57 原文链接
阅读:67 评论:0 查看评论

Viewing all articles
Browse latest Browse all 5930

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>