Android设计模式之观察者模式

观察者模式使用率较高,因为这个模式最重要的作用就是解耦,将观察者和被观察者解耦,使得它们之间的依赖性更小,甚至做到毫无依赖。

观察者模式的定义

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

观察者模式的使用场景

关联行为场景,需要注意的是,关联行为是可拆分的,而不是“组合”关系。

事件多级触发场景。

跨系统的消息交换场景,如消息队列、事件总线的处理机制。

 

观察者模式简单Demo 


import java.util.Observable;
import java.util.Observer;

public class Coder implements Observer {

    public static final String TAG = "zy";

    public String name;

    public Coder(String name) {
        this.name = name;
    }

    @Override
    public void update(Observable o, Object arg) {
        Log.v(TAG, "Hi, " + name + ", DeTechFrontier更新啦,内容:" + arg);
    }

    @Override
    public String toString() {
        return "Coder{" +
                "name='" + name + '\'' +
                '}';
    }
}



package observer.gome.com.observerdemo;

import java.util.Observable;

public class DevTechFrontier extends Observable {

    public void postNewPublication(String content) {
        //标识状态或内容发生改变
        setChanged();
        //通知所有的观察者
        notifyObservers(content);
    }
}



public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);


        //被观察者角色
        DevTechFrontier devTechFrontier = new DevTechFrontier();
        //观察者
        Coder mrsimple = new Coder("mr.simple");
        Coder coder1 = new Coder("coder-1");
        Coder coder2 = new Coder("coder-2");
        Coder coder3 = new Coder("coder-3");

        //将观察者注册到可观察对象的观察者队列中
        devTechFrontier.addObserver(mrsimple);
        devTechFrontier.addObserver(coder1);
        devTechFrontier.addObserver(coder2);
        devTechFrontier.addObserver(coder3);

        //发布消息
        devTechFrontier.postNewPublication("新的一期开发者技术前线周报发布啦!");
    }
}

 

Log分析:

V/zy: Hi, coder-3, DeTechFrontier更新啦,内容:新的一期开发者技术前线周报发布啦!

V/zy: Hi, coder-2, DeTechFrontier更新啦,内容:新的一期开发者技术前线周报发布啦!

V/zy: Hi, coder-1, DeTechFrontier更新啦,内容:新的一期开发者技术前线周报发布啦!

V/zy: Hi, mr.simple, DeTechFrontier更新啦,内容:新的一期开发者技术前线周报发布啦!

 

Observer和Obervable是JDK的内置类型,这里的Observer是抽象观察者角色,Coder扮演的是具体观察者角色;Observable对应的是抽象主题角色,DevTechFrontier则是具体主题的角色。Coder是具体的观察者,它们订阅了DevTechFrontier这个具体的可观察对象,当DevTechFrontier有更新时,会遍历所有的观察者(这里是Coder),然后给这些观察者对象发布一个更新消息,即调用Coder的update方法,这样就达到了一对多的通知功能。在整个过程中,通知系统都依赖Oberver和Obervable这些抽象类,因此,对于Coder和DevTechFrontier完全没有耦合,保证了订阅系统的灵活性、可扩展性。

 

Android中的观察者模式

/**
 * Common base class of common implementation for an {@link Adapter} that can be
 * used in both {@link ListView} (by implementing the specialized
 * {@link ListAdapter} interface) and {@link Spinner} (by implementing the
 * specialized {@link SpinnerAdapter} interface).
 */
public abstract class BaseAdapter implements ListAdapter, SpinnerAdapter {
       //数据集观察者
private final DataSetObservable mDataSetObservable = new DataSetObservable();

public void registerDataSetObserver(DataSetObserver observer) {
        mDataSetObservable.registerObserver(observer);
    }

    public void unregisterDataSetObserver(DataSetObserver observer) {
        mDataSetObservable.unregisterObserver(observer);
    }
    
   /**
     * Notifies the attached observers that the underlying data has been changed
     * and any View reflecting the data set should refresh itself.
    * //当数据集发生变化,通知所有观察者
     */
    public void notifyDataSetChanged() {
        mDataSetObservable.notifyChanged();
    }
}

 

由上述代码可知:BaseAdapter是一个观察者模式,BaseAdpater是如何运作的?先到mDataSetObservable.notifyChanged();函数看看: 

public class DataSetObservable extends Observable<DataSetObserver> {
    /**
     * Invokes {@link DataSetObserver#onChanged} on each observer.
     * Called when the contents of the data set have changed.  The recipient
     * will obtain the new contents the next time it queries the data set.
    * 调用每一个观察者的onChanged()函数来通知它们  被观察发生了改变。
     */
    public void notifyChanged() {
        synchronized(mObservers) {
            // since onChanged() is implemented by the app, it could do anything, including
            // removing itself from {@link mObservers} - and that could cause problems if
            // an iterator is used on the ArrayList {@link mObservers}.
            // to avoid such problems, just march thru the list in the reverse order.
            for (int i = mObservers.size() - 1; i >= 0; i--) {
                //调用所有观察者的onChanged方法
                mObservers.get(i).onChanged();
            }
        }
    }
    ... ...
}

mDataSetObservable.notifyChanged();中遍历所有的观察者,并且调用它们的onChanged方法,从而告知观察者的变化。

 

观察者就是ListView通过setAdapter方法设置Adapter产生的。

/**
 * Sets the data behind this ListView.
 *
 * The adapter passed to this method may be wrapped by a {@link WrapperListAdapter},
 * depending on the ListView features currently in use. For instance, adding
 * headers and/or footers will cause the adapter to be wrapped.
 *
 * @param adapter The ListAdapter which is responsible for maintaining the
 *        data backing this list and for producing a view to represent an
 *        item in that data set.
 *
 * @see #getAdapter()
 */
@Override
public void setAdapter(ListAdapter adapter) {
   //如果已经有了一个Adapter,那么先注销Adapter对应的观察者
    if (mAdapter != null && mDataSetObserver != null) {
        mAdapter.unregisterDataSetObserver(mDataSetObserver);
    }

    resetList();
    mRecycler.clear();

    if (mHeaderViewInfos.size() > 0|| mFooterViewInfos.size() > 0) {
        mAdapter = wrapHeaderListAdapterInternal(mHeaderViewInfos, mFooterViewInfos, adapter);
    } else {
        mAdapter = adapter;
    }

    mOldSelectedPosition = INVALID_POSITION;
    mOldSelectedRowId = INVALID_ROW_ID;

    // AbsListView#setAdapter will update choice mode states.
    super.setAdapter(adapter);

    if (mAdapter != null) {
        mAreAllItemsSelectable = mAdapter.areAllItemsEnabled();
        mOldItemCount = mItemCount;
       //获取数据的数量
        mItemCount = mAdapter.getCount();
        checkFocus();

//注意这里:创建一个数据集观察者
        mDataSetObserver = new AdapterDataSetObserver();
       //将这个观察者注册到Adapter中,实际上是注册到DataSetObserverObservable中
        mAdapter.registerDataSetObserver(mDataSetObserver);

        mRecycler.setViewTypeCount(mAdapter.getViewTypeCount());

        int position;
        if (mStackFromBottom) {
            position = lookForSelectablePosition(mItemCount - 1, false);
        } else {
            position = lookForSelectablePosition(0, true);
        }
        setSelectedPositionInt(position);
        setNextSelectedPositionInt(position);

        if (mItemCount == 0) {
            // Nothing selected
            checkSelectionChanged();
        }
    } else {
        mAreAllItemsSelectable = true;
        checkFocus();
        // Nothing selected
        checkSelectionChanged();
    }

    requestLayout();
}

 

从程序中可以看到,在设置Adapter时会构建一个AdapterDataSetObserver,这就是上面所说的观察者,最后,将这个观察者注册到Adapter中,这样我们的被观察者(Adapter)和观察者(AdapterDataSetObserver)都有了。这个时候可能就有点不明白,AdapterDataSetObserver是什么?它是如何运作的?那么就先来看看AdapterDataSetObserver,AdapterDataSetObserver定义在ListView的父类AbsListView汇总,具体代码如下。

 

#AbsListView
public abstract class AbsListView extends AdapterView<ListAdapter> implements TextWatcher,
        ViewTreeObserver.OnGlobalLayoutListener, Filter.FilterListener,
        ViewTreeObserver.OnTouchModeChangeListener,
        RemoteViewsAdapter.RemoteAdapterConnectionCallback {
        ... ...
}

/**
* Should be used by subclasses to listen to changes in the dataset
*/
#AbsListView
AdapterDataSetObserver mDataSetObserver;


#AdapterDataSetObserver 是 AbsListView的内部类
  class AdapterDataSetObserver extends AdapterView<ListAdapter>.AdapterDataSetObserver {
        @Override
        public void onChanged() {
            super.onChanged();
            if (mFastScroll != null) {
                mFastScroll.onSectionsChanged();
            }
        }

        @Override
        public void onInvalidated() {
            super.onInvalidated();
            if (mFastScroll != null) {
                mFastScroll.onSectionsChanged();
            }
        }
    }

AdapterDataSetObserver又继承自父类AdapterView的AdapterDataSetObserver,具体代码如下:

public abstract class AdapterView<T extends Adapter> extends ViewGroup {
    ... ...
}

#AdapterDataSetObserver  是  AdapterView     的内部类
class AdapterDataSetObserver extends DataSetObserver {

    private Parcelable mInstanceState = null;


//上文讲过,调用Adapter的notifyDataSetChanged时会调用所有观察者的onChanged方法,核心实现就在这里:

//上文讲过,调用Adapter的notifyDataSetChanged时会调用所有观察者的onChanged方法,核心实现就在这里。
    @Override
    public void onChanged() {
        mDataChanged = true;
        mOldItemCount = mItemCount;
      //获取Adapter中数据的数量
        mItemCount = getAdapter().getCount();

        // Detect the case where a cursor that was previously invalidated has
        // been repopulated with new data.
        if (AdapterView.this.getAdapter().hasStableIds() && mInstanceState != null
                && mOldItemCount == 0 && mItemCount > 0) {
            AdapterView.this.onRestoreInstanceState(mInstanceState);
            mInstanceState = null;
        } else {
            rememberSyncState();
        }
        checkFocus();
       //重新布局ListView、GridView等AdapterView组件
        requestLayout();
    }

    @Override
    public void onInvalidated() {
        mDataChanged = true;

        if (AdapterView.this.getAdapter().hasStableIds()) {
            // Remember the current state for the case where our hosting activity is being
            // stopped and later restarted
            mInstanceState = AdapterView.this.onSaveInstanceState();
        }

        // Data is invalid so we should reset our state
        mOldItemCount = mItemCount;
        mItemCount = 0;
        mSelectedPosition = INVALID_POSITION;
        mSelectedRowId = INVALID_ROW_ID;
        mNextSelectedPosition = INVALID_POSITION;
        mNextSelectedRowId = INVALID_ROW_ID;
        mNeedSync = false;

        checkFocus();
        requestLayout();
    }

    public void clearSavedState() {
        mInstanceState = null;
    }
}

 //到这里就可以明白了:当ListView数据发生改变时,调用Adapter的notifyDataSetChanged函数,这个函数又会调用DataSetObservable的notifyChanged函数,这个函数又会调用所有观察者(AdapterDataSetObserver ),的onChanged方法,在onChanged函数中又会调用ListView重新布局的函数使得ListView刷新界面,这就是一个观察者模式。

最后整理一下这个过程,AdapterView中有一个内部类AdapterDataSetObserver,在ListView中设置Adapter时会构建一个AdapterDataSetObserver,并且注册到Adapter中,这就是一个观察者。而Adpater中包含一个数据集可观察者DataSetObservable,在数据数量发生变更时,开发者手动调用Adapter.notifyDataSetChanged,而notifyDataSetChanged实际上会调用DataSetObservable的notifyChanged函数,该函数会遍历所有观察者的onChanged函数。在AdapterDataSetObserver的onChanged函数中会获取Adapter中数据集的新数量,然后调用ListView的requestLayout方法进行重新布局,更新用户界面。

 

《Android源码设计模式》

 

发布了161 篇原创文章 · 获赞 156 · 访问量 10万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览