上一篇推荐了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偷梁换柱了。