剖析MergeAdapter

上一篇推荐了mergerAdapter,本文我们看看MergeAdapter是如何实现的。

认真看了一下,其实原理不难懂,代码也不多,只有五百行左右。

import android.database.DataSetObserver;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ListAdapter;
import android.widget.SectionIndexer;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * Adapter that merges multiple child adapters and views
 * into a single contiguous whole.
 * <p>
 * Adapters used as pieces within MergeAdapter must have
 * view type IDs monotonically increasing from 0. Ideally,
 * adapters also have distinct ranges for their row ids, as
 * returned by getItemId().
 *
 * SectionIndexer:给Adapter去实现、用来在AbsListView中实现section之间的快速滚动的接口
 *
 */
public class MergeAdapter extends BaseAdapter implements SectionIndexer {

    //缓存的数据结构对象
    protected PieceStateRoster pieces = new PieceStateRoster();
    /**
     * Stock constructor, simply chaining to the superclass.
     */
    public MergeAdapter() {
        super();
    }

    /**
     * Adds a new adapter to the roster of things to appear in
     * the aggregate list.
     *
     * 列表中添加adapter,并且注册adapter的观察者
     *
     * @param adapter Source for row views for this section
     */
    public void addAdapter(ListAdapter adapter) {
        pieces.add(adapter);
        adapter.registerDataSetObserver(new CascadeDataSetObserver());
    }

    /**
     * Adds a new View to the roster of things to appear in
     * the aggregate list.
     *
     * @param view Single view to add
     *
     * 添加一个View
     */
    public void addView(View view) {
        addView(view, false);
    }

    /**
     * Adds a new View to the roster of things to appear in
     * the aggregate list.
     *
     * @param view    Single view to add
     * @param enabled false if views are disabled, true if enabled
     *
     * 初始化一个View队列,并且将View加入到队列中
     *  最后调用addView
     */
    public void addView(View view, boolean enabled) {
        ArrayList<View> list = new ArrayList<View>(1);

        list.add(view);

        addViews(list, enabled);
    }

    /**
     * Adds a list of views to the roster of things to appear
     * in the aggregate list.
     *
     * @param views List of views to add
     */
    public void addViews(List<View> views) {
        addViews(views, false);
    }

    /**
     * Adds a list of views to the roster of things to appear
     * in the aggregate list.
     *
     * @param views   List of views to add
     * @param enabled false if views are disabled, true if enabled
     *
     *                初始化一个View的adapter,并将view集合设置到adapter
     *                所以最终addView的view还是放到adapter,潜移默化的将view
     *                头换成了adapter,并且调用addAdapter方法。
     *
     *
     */
    public void addViews(List<View> views, boolean enabled) {
        if (enabled) {
            addAdapter(new EnabledSackAdapter(views));
        } else {
            addAdapter(new SackOfViewsAdapter(views));
        }
    }

    /**
     * Get the data item associated with the specified
     * position in the data set.
     *
     * @param position Position of the item whose data we want
     *
     *                 这里的getItem最终是调用各自adapter的getItem(piece.getItem(position))方法。
     */
    @Override
    public Object getItem(int position) {
        for (ListAdapter piece : getPieces()) {
            int size = piece.getCount();

            if (position < size) {
                return (piece.getItem(position));
            }

            position -= size;
        }

        return (null);
    }

    /**
     * Get the adapter associated with the specified position
     * in the data set.
     *
     * @param position Position of the item whose adapter we want
     *
     *                 获取特定位置(position)的adapter
     */
    public ListAdapter getAdapter(int position) {
        for (ListAdapter piece : getPieces()) {
            int size = piece.getCount();

            if (position < size) {
                return (piece);
            }

            position -= size;
        }

        return (null);
    }

    /**
     * How many items are in the data set represented by this
     * Adapter.
     * 这里的count是每个adapter的条目的总和
     */
    @Override
    public int getCount() {
        int total = 0;
        for (ListAdapter piece : getPieces()) {
            total += piece.getCount();
        }

        return (total);
    }

    /**
     * Returns the number of types of Views that will be
     * created by getView().
     * 每个adapter类型的总和
     */
    @Override
    public int getViewTypeCount() {
        int total = 0;

        for (PieceState piece : pieces.getRawPieces()) {
            total += piece.adapter.getViewTypeCount();
        }

        return (Math.max(total, 1)); // needed for
        // setListAdapter() before
        // content add'
    }

    /**
     * Get the type of View that will be created by getView()
     * for the specified item.
     *
     * @param position Position of the item whose data we want
     *
     *                 获取itemView的条目类型
     */
    @Override
    public int getItemViewType(int position) {
        int typeOffset = 0;
        int result = -1;

        for (PieceState piece : pieces.getRawPieces()) {
            if (piece.isActive) {

                int size = piece.adapter.getCount();

                if (position < size) {
                    result = typeOffset + piece.adapter.getItemViewType(position);
                    break;
                }
                position -= size;
            }

            typeOffset += piece.adapter.getViewTypeCount();
        }
        return (result);
    }

    /**
     * Are all items in this ListAdapter enabled? If yes it
     * means all items are selectable and clickable.
     * 默认Adapter中所有列表项都是不可点击和不可选择的
     */
    @Override
    public boolean areAllItemsEnabled() {
        return (false);
    }

    /**
     * Returns true if the item at the specified position is
     * not a separator.
     * position所指的列表项不需要分行符
     * @param position Position of the item whose data we want
     */
    @Override
    public boolean isEnabled(int position) {
        for (ListAdapter piece : getPieces()) {
            int size = piece.getCount();

            if (position < size) {
                return (piece.isEnabled(position));
            }

            position -= size;
        }

        return (false);
    }

    /**
     * Get a View that displays the data at the specified
     * position in the data set.
     *
     * @param position    Position of the item whose data we want
     * @param convertView View to recycle, if not null
     * @param parent      ViewGroup containing the returned View
     *                    这里调用自己adapter的getview方法
     */
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        for (ListAdapter piece : getPieces()) {
            int size = piece.getCount();

            if (position < size) {

                return (piece.getView(position, convertView, parent));
            }

            position -= size;
        }

        return (null);
    }

    /**
     * Get the row id associated with the specified position
     * in the list.
     *
     * @param position Position of the item whose data we want
     */
    @Override
    public long getItemId(int position) {
        for (ListAdapter piece : getPieces()) {
            int size = piece.getCount();

            if (position < size) {
                return (piece.getItemId(position));
            }

            position -= size;
        }

        return (-1);
    }

    @Override
    public int getPositionForSection(int section) {
        int position = 0;

        for (ListAdapter piece : getPieces()) {
            if (piece instanceof SectionIndexer) {
                Object[] sections = ((SectionIndexer) piece).getSections();
                int numSections = 0;

                if (sections != null) {
                    numSections = sections.length;
                }

                if (section < numSections) {
                    return (position + ((SectionIndexer) piece).getPositionForSection(section));
                } else if (sections != null) {
                    section -= numSections;
                }
            }

            position += piece.getCount();
        }

        return (0);
    }

    @Override
    public int getSectionForPosition(int position) {
        int section = 0;

        for (ListAdapter piece : getPieces()) {
            int size = piece.getCount();

            if (position < size) {
                if (piece instanceof SectionIndexer) {
                    return (section + ((SectionIndexer) piece).getSectionForPosition(position));
                }

                return (0);
            } else {
                if (piece instanceof SectionIndexer) {
                    Object[] sections = ((SectionIndexer) piece).getSections();

                    if (sections != null) {
                        section += sections.length;
                    }
                }
            }

            position -= size;
        }

        return (0);
    }

    @Override
    public Object[] getSections() {
        ArrayList<Object> sections = new ArrayList<Object>();

        for (ListAdapter piece : getPieces()) {
            if (piece instanceof SectionIndexer) {
                Object[] curSections = ((SectionIndexer) piece).getSections();

                if (curSections != null) {
                    Collections.addAll(sections, curSections);
                }
            }
        }

        if (sections.size() == 0) {
            return (new String[0]);
        }

        return (sections.toArray(new Object[0]));
    }

    /**
     * 设置adapter是否可以显示
     * @param adapter
     * @param isActive
     */
    public void setActive(ListAdapter adapter, boolean isActive) {
        pieces.setActive(adapter, isActive);
        notifyDataSetChanged();
    }

    /**
     * 设置view是否可以显示
     * @param v
     * @param isActive
     */
    public void setActive(View v, boolean isActive) {
        pieces.setActive(v, isActive);
        notifyDataSetChanged();
    }

    /**
     * 获取所有可以显示的adapter
     * @return
     */
    protected List<ListAdapter> getPieces() {
        return (pieces.getPieces());
    }

    /**
     * 封装adapter和isActive的数据结构
     */
    private static class PieceState {
        ListAdapter adapter;
        boolean isActive = true;

        PieceState(ListAdapter adapter, boolean isActive) {
            this.adapter = adapter;
            this.isActive = isActive;
        }
    }

    /**
     * PieceStateRoster类
     * 用于管理Adapter
     */
    private static class PieceStateRoster {
        protected ArrayList<PieceState> pieces = new ArrayList<PieceState>();
        protected ArrayList<ListAdapter> active = null;

        /**
         * 加入一个adapter到管理队列中
         * @param adapter
         */
        void add(ListAdapter adapter) {
            pieces.add(new PieceState(adapter, true));
        }

        /**
         * 设置adapter是否可以显示
         * @param adapter
         * @param isActive false不显示,true显示
         */
        void setActive(ListAdapter adapter, boolean isActive) {
            for (PieceState state : pieces) {
                if (state.adapter == adapter) {
                    state.isActive = isActive;
                    active = null;
                    break;
                }
            }
        }

        /**
         * 设置View是否可显示
         * @param v
         * @param isActive false不显示,true显示
         */
        void setActive(View v, boolean isActive) {
            for (PieceState state : pieces) {
                if (state.adapter instanceof SackOfViewsAdapter &&
                        ((SackOfViewsAdapter) state.adapter).hasView(v)) {
                    state.isActive = isActive;
                    active = null;
                    break;
                }
            }
        }

        /**
         * 获取adapter队列
         * @return
         */
        List<PieceState> getRawPieces() {
            return (pieces);
        }

        /**
         * 获取显示的adapter队列
         * @return
         */
        List<ListAdapter> getPieces() {
            if (active == null) {
                active = new ArrayList<ListAdapter>();

                for (PieceState state : pieces) {
                    if (state.isActive) {
                        active.add(state.adapter);
                    }
                }
            }

            return (active);
        }
    }

    /**
     * 封装SackOfViewsAdapter
     *
     */
    private static class EnabledSackAdapter extends SackOfViewsAdapter {
        public EnabledSackAdapter(List<View> views) {
            super(views);
        }

        /**
         * Adapter中所有列表项都是可点击和可选择的
         * @return
         */
        @Override
        public boolean areAllItemsEnabled() {
            return (true);
        }

        /**
         * position所指的列表项需要分行符
         * @param position
         * @return
         */
        @Override
        public boolean isEnabled(int position) {
            return (true);
        }
    }

    /**
     *listview观察者模式
     *
     */
    private class CascadeDataSetObserver extends DataSetObserver {
        @Override
        public void onChanged() {
            notifyDataSetChanged();
        }

        @Override
        public void onInvalidated() {
            notifyDataSetInvalidated();
        }
    }
}
复制代码

这是一个合并多个子适配器和视图的适配器。首先PieceStateRoster是子适配器管理器,这个管理器具体的解释在已经在文件中做了注释了。addAdapter会将子适配器加入到适配器的管理器的队列当中,pieces.add(new PieceState(adapter, true)),PieceState就是封装了Adapter和isActive的集合。isActive决定是否显示出来。加入适配器的管理器之后就会注册adapter的数据监听器。如果适配器监听到数据就会调用adapter的notifyDataSetChanged(); 我们在看看addView方法,addView方法最终会调用addAdapter。

public void addViews(List<View> views, boolean enabled) {
        if (enabled) {
            addAdapter(new EnabledSackAdapter(views));
        } else {
            addAdapter(new SackOfViewsAdapter(views));
        }
    }
复制代码

这里构造adapter,并将views传入,然后调用addAdapter方法将构造的adapter加入到适配器管理的队列中,这时跟平常传入的adapter没啥两样了,PieceState管理器对适配器统一管理。这里做了一个偷梁换柱。表面上我们是通过addview传入View,实际上是MergeAdapter已经偷偷帮我们换了一个adapter。

 @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        for (ListAdapter piece : getPieces()) {
            int size = piece.getCount();

            if (position < size) {

                return (piece.getView(position, convertView, parent));
            }

            position -= size;
        }

        return (null);
    }
复制代码

merge的getview方法,还是会调用子适配器的getview方法。 其余的方法、对象,文件中均有注释。

public class SackOfViewsAdapter extends BaseAdapter {
	  
    private List<View> mViewList = null;
  
    /** 
     * 构造大小为count,值为null的view集合,这时需要子类重写newView函数 
     */  
    public SackOfViewsAdapter(int count) {  
        super();  
        mViewList = new ArrayList<View>(count);
        for (int i = 0; i < count; i++) {
            mViewList.add(null);  
        }
    }  
  
    /** 
     * 由传入的view集合直接给容器赋值,如果view集合中有为null值的view,则子类必须实现newView函数 
     */  
    public SackOfViewsAdapter(List<View> views) {
        super();  
        this.mViewList = views;  
    }  
    
    /** 
     * 移除全部
     */  
    public void removeAll() { 
    	mViewList.clear();
    }  
    
    /** 
     * 移除一项
     */  
    public void remove(int position) { 
    	if(position >= 0 && position < mViewList.size())
    	{
    		mViewList.remove(position);
    	}
    }  
    
    /** 
     * 移除一项
     */  
    public void remove(View v) {
    	mViewList.remove(v);
    }  
    
    /** 
     *添加一项
     */  
    public void add(View v) {
    	mViewList.add(v);
    }  
  
    /** 
     * 返回对应位置的列表项 
     */  
    @Override
    public Object getItem(int position) {
        return mViewList.get(position);  
    }  
  
    /** 
     * 返回列表项的个数 
     */  
    @Override
    public int getCount() {  
        return mViewList.size();  
    }
  
    /** 
     * getView函数创建的列表项类型个数 
     */  
    @Override
    public int getViewTypeCount() {  
        return getCount();  
    }  
  
    /** 
     * getView函数创建的view类型值,这里以view所在的位置作为类型值 
     */  
    @Override
    public int getItemViewType(int position) {  
        return position;  
    }  
  
    /** 
     * 如果Adapter中所有列表项都是可点击和可选择的,则返回true 
     */  
    @Override
    public boolean areAllItemsEnabled() {  
        return false;  
    }  
  
    /** 
     * 如果position所指的列表项需要分行符,则返回true 
     */  
    @Override
    public boolean isEnabled(int position) {  
        return false;  
    }  
  
    /** 
     * 返回指定位置position的列表项的view 
     */  
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View result = mViewList.get(position);
  
        // 如果mViewList中的view为null,则需要调用newView函数来创建一个,该函数由子类来实现  
        if (result == null) {  
            result = newView(position, parent);  
            mViewList.set(position, result);  
        }  
        convertView = result;
        return convertView;  
    }
      
    /** 
     * 创建列表中指定位置的列表项,该函数有子类实现 
     */  
    protected View newView(int position, ViewGroup parent) {
        throw new RuntimeException("You must override newView()!");
    }  
  
    /** 
     * 获得指定位置的列表项的id 
     */  
    @Override
    public long getItemId(int position) {  
        return position;  
    }  
  
    /** 
     * 判断Adapter中是否存在某个指定的view 
     */  
    public boolean hasView(View v) {
        return mViewList.contains(v);  
    }  
  
}
复制代码

这个SackOfViewsAdapter就是addView时merge偷偷帮我们换上的adapter,就是一个显示view的适配器。

最后文件开头已经介绍了Adapter that merges multiple child adapters and views into a single contiguous whole.这是一个合并多个子适配器和视图的适配器,成为一个连续的整体。 要知道这里的addview最终被merge偷梁换柱了。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值