适配器模式

             适配器模式在我们工作开发的过程中经常碰到,从我们的代码中随处可见。像我们之前使用的ListView,GridView以及现在使用的RecyclerView到处都有Adapter的影子,那么我们今天来一起看看我们的适配器模式

 

定义:

适配器模式把一个类的接口变换为客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作

 

使用场景:

(1) 系统需要使用现有的类,而此类的接口不符合系统的需要,即接口不兼容

(2) 想要建立一个可以重复使用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作

(3) 需要一个统一的输出接口,而输入端的类型不可预知

 

模式:

适配器模式分为两种,即类适配器模式和对象适配器模式。对于类适配器而言, 其主要是通过继承类来实现适配的功能;而对于对象适配器而言,其主要是在类中持有辅助类的实例,从而达到适配的效果。那么现在我们就一起来看看在android源码当中适配器模式的运用。

 

Android源码中的适配器模式

在android中,适配器模式运用的最广泛的地方就是我们的容器,像之前我们经常用的ListView,GridView和现在经常使用的RecyclerView等等。今天,我们就以ListView为例,详细介绍一下适配器模式。我们知道ListView作为一个很重要的控件,它需要能够显示各种各样的视图,每个人需要的显示效果各不相同,显示的数据类型、数量等也千变万化,为了适应这种需求,android的做法是增加一个Adapter层来隔离变化,将ListView需要的关于Item View的接口抽象到Adapter对象中,并且在ListView内部调用Adapter这些接口完成布局等操作。这样只要用户实现了Adapter的接口,并且将该Adapter设置给ListView,ListView就可以按照用户设定的UI效果,数量,数据来显示每一项数据。

 

先来看下setAdapter

@Override
    public void setAdapter(ListAdapter adapter) {
	// 如果当前mAdapter不为空并且数据的观察者不为空
        if (mAdapter != null && mDataSetObserver != null) {
            // 解绑当前的观察者
	    mAdapter.unregisterDataSetObserver(mDataSetObserver);
        }

        resetList();
        mRecycler.clear();

	// 设置mAdapter的值
        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);

	// 如果mAdapter不为空
        if (mAdapter != null) {
            mAreAllItemsSelectable = mAdapter.areAllItemsEnabled();
            mOldItemCount = mItemCount;
            mItemCount = mAdapter.getCount();
            checkFocus();
            // 添加对Adapter的绑定
            mDataSetObserver = new AdapterDataSetObserver();
            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();
    }

注意看这里有一个很重要的字段mAdapter,但是在ListView当中你会发现找不到mAdapter的声明,那么mAdapter到底在哪里声明的呢?我们去找ListView的父类AbsListView,在AbsListView里面我们找到下面这行代码:

ListAdapter mAdapter;

那么ListAdapter里面又有些什么东西呢?

public interface ListAdapter extends Adapter {

    // 所有的条目是否可以点击
    public boolean areAllItemsEnabled();


    // 设置单个条目是否可以点击
    boolean isEnabled(int position);

}

ListAdapter是一个接口,它比较简单,接下来我们继续看Adapter

public interface Adapter {
  
    // 注册观察者
    void registerDataSetObserver(DataSetObserver observer);

    // 解除观察者
    void unregisterDataSetObserver(DataSetObserver observer);

    // 获取数目条数
    int getCount();   
    
    // 获取Item
    Object getItem(int position);
    
    // 获取Item的id
    long getItemId(int position);
    
    /**
     * Indicates whether the item ids are stable across changes to the
     * underlying data.
     * 
     * @return True if the same id always refers to the same object.
     */
    boolean hasStableIds();
    
    // 获取View
    View getView(int position, View convertView, ViewGroup parent);
 
    // 忽略item的类型
    static final int IGNORE_ITEM_VIEW_TYPE = AdapterView.ITEM_VIEW_TYPE_IGNORE;
    
    // 获取Item的类型
    int getItemViewType(int position);
    
    // 获取Item类型的数量
    int getViewTypeCount();
    
    static final int NO_SELECTION = Integer.MIN_VALUE;
 
   
    boolean isEmpty();

  
    default @Nullable CharSequence[] getAutofillOptions() {
        return null;
    }
}

我们发现,在这个接口里面,有很多我们熟悉的方法,看到这里,估计大家都明白了,ListView通过Adapter模式持有ListAdapter的引用,从而实现加载每个Item View的布局,并且进行数据绑定的功能。

 

你可能感兴趣的:(设计模式)