zoukankan      html  css  js  c++  java
  • Android源码与设计模式之notifyDataSetChanged()方法与观察者模式

    BaseAdapter在调用notifyDataSetChanged()方法后,GridView就刷新了,下面从源码角度对此原理进行剖析。

    首先进到BaseAdapter中查看其notifyDataSetChanged()方法,发现它调用了DataSetObservable的notifyChanged()方法

    public abstract class BaseAdapter{
    private final DataSetObservable mDataSetObservable = new DataSetObservable();
    
    public void registerDataSetObserver(DataSetObserver observer) {
            mDataSetObservable.registerObserver(observer);
        }
    
        public void unregisterDataSetObserver(DataSetObserver observer) {
            mDataSetObservable.unregisterObserver(observer);
        }
    ...
        public void notifyDataSetChanged() {
            mDataSetObservable.notifyChanged();
        }
    ...
    }

    接着查看DataSetObservable的notifyChanged()方法,发现它调用了mObservers.get(i)的onChanged()方法,即DataSetObserver的onChanged()方法。

    public class DataSetObservable extends Observable<DataSetObserver> {
    ...
        public void notifyChanged() {
            synchronized(mObservers) {
                for (int i = mObservers.size() - 1; i >= 0; i--) {
                    mObservers.get(i).onChanged();
                }
            }
        }
    ... }

    其中的mObservers是在这里赋值的。

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

    接下来寻找registerObserver()方法是在哪里调用的,发现刚才的BaseAdapter的registerDataSetObserver()方法调用了它。

    而此方法是在GridView的setAdapter方法中被调用的。

    ...class GridView ...{
    ...
    @Override
        public void setAdapter(ListAdapter adapter) {
            ...
    
            resetList();
            mRecycler.clear();        
            mAdapter = adapter;
    
        ...
    if (mAdapter != null) { ... mDataSetObserver = new AdapterDataSetObserver(); mAdapter.registerDataSetObserver(mDataSetObserver); ... } else { checkFocus(); // Nothing selected checkSelectionChanged(); } requestLayout(); } ... }

    传进去的是AdapterDataSetObserver这个类,具体的刷新动作就是在这个类的onChanged()方法中完成的。

    class AdapterDataSetObserver extends DataSetObserver
     2   {
     3     private Parcelable mInstanceState = null;
     4 
     5     AdapterDataSetObserver() {
     6     }
     7     public void onChanged() { mDataChanged = true;
     8       mOldItemCount = mItemCount;
     9       mItemCount = getAdapter().getCount();
    10 
    11       if ((getAdapter().hasStableIds()) && (mInstanceState != null) && (mOldItemCount == 0) && (mItemCount > 0))
    12       {
    13         onRestoreInstanceState(mInstanceState);
    14         mInstanceState = null;
    15       } else {
    16         rememberSyncState();
    17       }
    18       checkFocus();
    19       requestLayout();
    20     }
    21     //...省略不必要代码
    22 }

    它会调用requestLayout()方法,又去调用scheduleTraversals()方法,这是刷新view的一个相关方法,具体实现本文暂不分析。

    1     public void requestLayout() {
    2         checkThread();
    3         mLayoutRequested = true;
    4         scheduleTraversals();
    5     }

    到此可以看到notifyDataSetChanged是怎么一步步实现的了。

    可以看到这个流程充分利用了观察者模式来激发view刷新。

    view.setAdapter(adapter)传入的adapter就是被观察者,而观察者是GridView父类AbsListView的成员变量mDataSetObserver。所以刷新的界面被选定为此gridview。

    这里的Observer相关的类都是由android实现的,但是与java实现思路相同。

  • 相关阅读:
    eslint 的 env 配置是干嘛使的?
    cookie httpOnly 打勾
    如何定制 antd 的样式(theme)
    剑指 Offer 66. 构建乘积数组
    剑指 Offer 65. 不用加减乘除做加法
    剑指 Offer 62. 圆圈中最后剩下的数字
    剑指 Offer 61. 扑克牌中的顺子
    剑指 Offer 59
    剑指 Offer 58
    剑指 Offer 58
  • 原文地址:https://www.cnblogs.com/BlogCommunicator/p/6868635.html
Copyright © 2011-2022 走看看