RecyclerView Adapter 优雅封装,一个Adapter搞定所有列表

wxpletgo 7年前
   <p>项目中,我们用得最多的元素就是列表了,在Android 中,实现列表用原生的RecyclerView就能满足需求,关于RecyclerView 的基础使用这里不做过多的介绍,网上有太多的博文介绍了。本篇文章将介绍自己封装的一个Adapter,帮你快速高效的添加一个列表(包括单 Item 列表和多item列表)。</p>    <h3>理念</h3>    <p>1, 构造一个通用的Adapter模版,避免每添加一个列表就要写一个Adapter,避免写Adapter中的大量重复代码。</p>    <p>2,通过组装的方式来构建Adapter,将每一种(ViewType不同的)Item抽象成一个单独组件,Adapter 就是一个壳,我们只需要向Adapter中添加Item就行,这样做的好处就是减少耦合,去掉一种item 或者添加一种item对于列表是没有任何影响的。</p>    <p>3,高内聚,低耦合,扩展方便。</p>    <h3>思路</h3>    <p>为每一种 viewType 定义一个Cell,Cell就是上面提到的独立组件,它负责创建ViewHolder,数据绑定和逻辑处理。它有2个重要的方法,onCreateViewHolder 负责创建ViewHolder,onBindViewHolder负责数据绑定,这两个方法的定义和生命周期同Adapter种的2个方法一样,事实上,Adapter 中的onCreateViewHolder和onBindViewHolder 最终调用的是Cell中的方法。</p>    <p>一种 ViewType 对应一个Cell</p>    <p>看一个示例:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/042a2de8c93ed02094562f8e303b9402.png"></p>    <p style="text-align:center">cell_simple.png</p>    <p>如上图:以豆瓣APP的首页为例,文章包含图片和视频的两个Item 的布局是不同的,因此,可以添加两个Cell(ImageCell和VideoCell)来分别处理这两种Item。</p>    <p>有了Cell之后,要向列表添加添加Header和Footer 的需求就很简单了,我们直接添加一个HeaderCell和FooterCell 就可以了,也不用更改Adapter代码,是不是很方便。此外,还可以用Cell实现列表LoadMore(加载更多)状态、Loadding(加载中)状态、Empty(空页面)状态、Error(出错)状态 View的显示。</p>    <h3>包结构</h3>    <p style="text-align:center"><img src="https://simg.open-open.com/show/8a9724ba1c906838dceb1f11f84ce71b.png"></p>    <p style="text-align:center">rv_pakage.png</p>    <p>介绍: <strong>1,base:</strong> base包下面为Lib的主要代码,一个Cell接口和三个抽象类,分别抽取了Adapter,ViewHolder,Cell的公共逻辑。</p>    <p>2,cell:cell包下面有4个cell,分别显示列表的LoadMore,Loading,Empty,Error状态。</p>    <p>3,fragment:有一个Fragment抽象类,定义了一个UI模版(不需要额外添加布局文件),要实现列表的界面只需要继承AbsBaseFragment,实现几个方法添加数据就OK。</p>    <h3>具体代码</h3>    <p>1,Cell 接口定义</p>    <pre>  <code class="language-java">/**   * Created by zhouwei on 17/1/19.   */    public interface Cell {      /**       * 回收资源       *       */      public void releaseResource();        /**       * 获取viewType       * @return       */      public  int getItemType();        /**       * 创建ViewHolder       * @param parent       * @param viewType       * @return       */      public RVBaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType);        /**       * 数据绑定       * @param holder       * @param position       */      public  void onBindViewHolder(RVBaseViewHolder holder, int position);  }</code></pre>    <p>定义了4个方法,除了回收资源的方法releaseResource(),其它三个和Adapter中的一样。</p>    <p>2,RVBaseCell</p>    <pre>  <code class="language-java">/**   * Created by zhouwei on 17/1/19.   */    public  abstract class RVBaseCell<T> implements Cell {        public RVBaseCell(T t){          mData = t;      }      public T mData;        @Override      public void releaseResource() {          // do nothing          // 如果有需要回收的资源,子类自己实现      }  }</code></pre>    <p>抽象类,接受一个范型T(Cell接受的数据实体),实现了releaseResource方法,但什么事也没干,因为有很多简单的Cell没有资源回收,就不需要实现。如果子类Cell 有资源回收,重写这个方法就可以了。</p>    <p>3, RVBaseViewHolder</p>    <pre>  <code class="language-java">/**   * Created by zhouwei on 17/1/19.   */    public class RVBaseViewHolder extends RecyclerView.ViewHolder{      private SparseArray<View> views;      private View mItemView;      public RVBaseViewHolder(View itemView) {          super(itemView);          views = new SparseArray<>();          mItemView = itemView;        }        /**       * 获取ItemView       * @return       */      public View getItemView() {          return mItemView;      }        public View getView(int resId) {          return retrieveView(resId);      }        public TextView getTextView(int resId){          return retrieveView(resId);      }        public ImageView getImageView(int resId){          return retrieveView(resId);      }        public Button getButton(int resId){          return retrieveView(resId);      }        @SuppressWarnings("unchecked")      protected <V extends View> V retrieveView(int viewId){          View view = views.get(viewId);          if(view == null){              view = mItemView.findViewById(viewId);              views.put(viewId,view);          }          return (V) view;      }        public void setText(int resId,CharSequence text){            getTextView(resId).setText(text);      }        public void setText(int resId,int strId){          getTextView(resId).setText(strId);      }    }</code></pre>    <p>以前写Adapter的时候,每一种viewType 都对应了一个ViewHolder,其中有大量的findViewById绑定视图,有了RVBaseViewHolder,再也不需要定义ViewHolder了,通过id获取View就行,View用SparseArray 保存进行了复用,避免每一次都find。</p>    <p>4,RVBaseAdapter</p>    <pre>  <code class="language-java">/**   * Created by zhouwei on 17/1/19.   */    public   abstract class RVBaseAdapter<C extends RVBaseCell>  extends RecyclerView.Adapter<RVBaseViewHolder>{      public static final String TAG = "RVBaseAdapter";      protected List<C> mData;        public RVBaseAdapter(){          mData = new ArrayList<>();      }        public void setData(List<C> data) {          addAll(data);          notifyDataSetChanged();      }        public List<C> getData() {          return mData;      }        @Override      public RVBaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {          for(int i=0;i<getItemCount();i++){              if(viewType == mData.get(i).getItemType()){                  return mData.get(i).onCreateViewHolder(parent,viewType);              }          }            throw new RuntimeException("wrong viewType");      }        @Override      public void onBindViewHolder(RVBaseViewHolder holder, int position) {          mData.get(position).onBindViewHolder(holder,position);      }        @Override      public void onViewDetachedFromWindow(RVBaseViewHolder holder) {          super.onViewDetachedFromWindow(holder);          Log.e(TAG,"onViewDetachedFromWindow invoke...");          //释放资源          int position = holder.getAdapterPosition();          //越界检查          if(position<0 || position>=mData.size()){              return;          }          mData.get(position).releaseResource();      }          @Override      public int getItemCount() {          return mData == null ? 0:mData.size();      }        @Override      public int getItemViewType(int position) {          return mData.get(position).getItemType();      }        /**       * add one cell       * @param cell       */      public void add(C cell){           mData.add(cell);           int index = mData.indexOf(cell);           notifyItemChanged(index);      }        public void add(int index,C cell){          mData.add(index,cell);          notifyItemChanged(index);      }        /**       * remove a cell       * @param cell       */      public void remove(C cell){          int indexOfCell = mData.indexOf(cell);          remove(indexOfCell);      }        public void remove(int index){          mData.remove(index);          notifyItemRemoved(index);      }        /**       *       * @param start       * @param count       */      public void remove(int start,int count){          if((start +count) > mData.size()){              return;          }          int size = getItemCount();          for(int i =start;i<size;i++){              mData.remove(i);          }            notifyItemRangeRemoved(start,count);      }              /**       * add a cell list       * @param cells       */      public void addAll(List<C> cells){          if(cells == null || cells.size() == 0){              return;          }          Log.e("zhouwei","addAll cell size:"+cells.size());          mData.addAll(cells);          notifyItemRangeChanged(mData.size()-cells.size(),mData.size());      }        public void addAll(int index,List<C> cells){          if(cells == null || cells.size() == 0){              return;          }          mData.addAll(index,cells);          notifyItemRangeChanged(index,index+cells.size());      }        public void clear(){          mData.clear();          notifyDataSetChanged();      }          /**       * 如果子类需要在onBindViewHolder 回调的时候做的操作可以在这个方法里做       * @param holder       * @param position       */      protected abstract void onViewHolderBound(RVBaseViewHolder holder, int position);    }</code></pre>    <p>RVBaseAdapter 继承 RecyclerView.Adapter,接受的是RVBaseCell类型,保存了一个Cell 列表。其中还有有添加、移除,清空、更新数据的方法。</p>    <p>注意其中几个方法:</p>    <p>1,getItemViewType:调用的是对应position Cell 的getItemViewType 方法。</p>    <p>2,onCreateViewHolder:调用Cell 的onCreateViewHolder 创建ViewHolder。</p>    <p>3,onBindViewHolder:调用对应Cell的onBindViewHolder 方法绑定数据</p>    <p>4,onViewDetachedFromWindow:资源回收</p>    <p>5,RVSimpleAdapter</p>    <pre>  <code class="language-java">/**   * Created by zhouwei on 17/1/23.   */    public class RVSimpleAdapter extends RVBaseAdapter{      public static final int ERROR_TYPE = Integer.MAX_VALUE -1;      public static final int EMPTY_TYPE = Integer.MAX_VALUE -2;      public static final int LOADING_TYPE = Integer.MAX_VALUE -3;      public static final int LOAD_MORE_TYPE = Integer.MAX_VALUE -4;        private EmptyCell mEmptyCell;      private ErrorCell mErrorCell;      private LoadingCell mLoadingCell;      private LoadMoreCell mLoadMoreCell;      //LoadMore 是否已显示      private boolean mIsShowLoadMore = false;        public RVSimpleAdapter(){          mEmptyCell = new EmptyCell(null);          mErrorCell = new ErrorCell(null);          mLoadingCell = new LoadingCell(null);          mLoadMoreCell = new LoadMoreCell(null);      }      @Override      protected void onViewHolderBound(RVBaseViewHolder holder, int position) {        }        @Override      public void onAttachedToRecyclerView(RecyclerView recyclerView) {          super.onAttachedToRecyclerView(recyclerView);          RecyclerView.LayoutManager manager = recyclerView.getLayoutManager();          //处理GridView 布局          if(manager instanceof GridLayoutManager){              final GridLayoutManager gridLayoutManager = (GridLayoutManager) manager;              gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {                  @Override                  public int getSpanSize(int position) {                      int viewType = getItemViewType(position);                      return (viewType == ERROR_TYPE|| viewType == EMPTY_TYPE || viewType == LOADING_TYPE                      ||viewType == LOAD_MORE_TYPE) ? gridLayoutManager.getSpanCount():1;                  }              });          }        }        @Override      public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) {          // 处理StaggeredGridLayoutManager 显示这个Span          int position = holder.getAdapterPosition();          int viewType = getItemViewType(position);          if(isStaggeredGridLayout(holder)){              if(viewType == ERROR_TYPE|| viewType == EMPTY_TYPE || viewType == LOADING_TYPE                      ||viewType == LOAD_MORE_TYPE){                    StaggeredGridLayoutManager.LayoutParams params = (StaggeredGridLayoutManager.LayoutParams) holder.itemView.getLayoutParams();                  //设置显示整个span                  params.setFullSpan(true);              }          }        }        private boolean isStaggeredGridLayout(RecyclerView.ViewHolder holder) {          ViewGroup.LayoutParams layoutParams = holder.itemView.getLayoutParams();          if (layoutParams != null && layoutParams instanceof StaggeredGridLayoutManager.LayoutParams) {              return true;          }          return false;      }        /**       * 显示LoadingView       * <p>请求数据时调用,数据请求完毕时调用{@link #hideLoading }</p>       * @see #showLoadingKeepCount(int)       */      public void showLoading(){        clear();        add(mLoadingCell);      }        public void showLoading(View loadingView){          if(loadingView == null){              showLoading();          }          clear();          mLoadingCell.setLoadingView(loadingView);          add(mLoadingCell);      }      /**       * 显示LoadingView       * <p>列表显示LoadingView并保留keepCount个Item</p>       * @param keepCount 保留的条目数量       */      public void showLoadingKeepCount(int keepCount){          if(keepCount < 0 || keepCount>mData.size()){              return;          }          remove(keepCount,mData.size() - keepCount);          if(mData.contains(mLoadingCell)){              mData.remove(mLoadingCell);          }          add(mLoadingCell);      }      /**       * hide Loading view       */      public void hideLoading(){          if(mData.contains(mLoadingCell)){              mData.remove(mLoadingCell);          }      }        /**       * 显示错误提示       * <p>当网络请求发生错误,需要在界面给出错误提示时,调用{@link #showError}</p>       * @see #showErrorKeepCount(int)       */      public void showError(){         clear();         add(mErrorCell);      }        /**       * 显示错误提示       * <p>当网络请求发生错误,需要在界面给出错误提示时,调用{@link #showErrorKeepCount(int)},并保留keepCount 条Item</p>       * @param keepCount 保留Item数量       */      public void showErrorKeepCount(int keepCount){          if(keepCount < 0 || keepCount>mData.size()){              return;          }          remove(keepCount,mData.size() - keepCount);          if(mData.contains(mErrorCell)){              mData.remove(mErrorCell);          }          add(mErrorCell);        }        /**       * 隐藏错误提示       */      public void hideErorr(){         if(mData.contains(mErrorCell)){             remove(mErrorCell);         }      }        /**       * 显示LoadMoreView       * <p>当列表滑动到底部时,调用{@link #showLoadMore()} 提示加载更多,加载完数据,调用{@link #hideLoadMore()}       * 隐藏LoadMoreView,显示列表数据。</p>       *       */      public void showLoadMore(){         if(mData.contains(mLoadMoreCell)){             return;         }         add(mLoadMoreCell);         mIsShowLoadMore = true;      }        /**       * 隐藏LoadMoreView       * <p>调用{@link #showLoadMore()}之后,加载数据完成,调用{@link #hideLoadMore()}隐藏LoadMoreView</p>       */      public void hideLoadMore(){         if(mData.contains(mLoadMoreCell)){             remove(mLoadMoreCell);             mIsShowLoadMore = false;         }      }        /**       * LoadMore View 是否已经显示       * @return       */      public boolean isShowLoadMore() {          return mIsShowLoadMore;      }        /**       *       * @param keepCount       */      public void showEmptyKeepCount(int keepCount){          if(keepCount < 0 || keepCount>mData.size()){              return;          }          remove(keepCount,mData.size() - keepCount);          if(mData.contains(mEmptyCell)){              mData.remove(mEmptyCell);          }          add(mEmptyCell);        }        /**       * 显示空view       * <p>当页面没有数据的时候,调用{@link #showEmpty()}显示空View,给用户提示</p>       */      public void showEmpty(){        clear();        add(mEmptyCell);      }        /**       * 隐藏空View       */      public void hideEmpty(){        if(mData.contains(mEmptyCell)){            remove(mEmptyCell);        }      }  }</code></pre>    <p>RVSimpleAdapter 是RVBaseAdapter 的默认实现类,添加了显示LoadMore View、Loading View 、Empty View、ErrorView 的功能。</p>    <p>6,AbsBaseFragment</p>    <pre>  <code class="language-java">/**   * Created by zhouwei on 17/2/3.   */    public abstract class AbsBaseFragment<T> extends Fragment {      protected RecyclerView mRecyclerView;      protected RVSimpleAdapter mBaseAdapter;      private FrameLayout mToolbarContainer;      protected SwipeRefreshLayout mSwipeRefreshLayout;      /**       * RecyclerView 最后可见Item在Adapter中的位置       */      private int mLastVisiblePosition = -1;        @Nullable      @Override      public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {          View view =  inflater.inflate(R.layout.base_fragment_layout,null);          return view;      }        @Override      public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {          super.onViewCreated(view, savedInstanceState);          mSwipeRefreshLayout = (SwipeRefreshLayout) view.findViewById(R.id.base_refresh_layout);          mToolbarContainer = (FrameLayout) view.findViewById(R.id.toolbar_container);          mRecyclerView = (RecyclerView) view.findViewById(R.id.base_fragment_rv);          mRecyclerView.setLayoutManager(initLayoutManger());          mBaseAdapter = initAdapter();          mRecyclerView.setAdapter(mBaseAdapter);          mSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {              @Override              public void onRefresh() {                  setRefreshing(true);                  onPullRefresh();              }          });          mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {              @Override              public void onScrolled(RecyclerView recyclerView, int dx, int dy) {                    RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();                  if(layoutManager instanceof LinearLayoutManager){                      mLastVisiblePosition = ((LinearLayoutManager)layoutManager).findLastVisibleItemPosition();                  }else if(layoutManager instanceof GridLayoutManager){                      mLastVisiblePosition = ((GridLayoutManager)layoutManager).findLastVisibleItemPosition();                  }else if(layoutManager instanceof StaggeredGridLayoutManager){                      StaggeredGridLayoutManager staggeredGridLayoutManager = (StaggeredGridLayoutManager) layoutManager;                      int []lastPositions = new int[staggeredGridLayoutManager.getSpanCount()];                      staggeredGridLayoutManager.findLastVisibleItemPositions(lastPositions);                      mLastVisiblePosition = findMax(lastPositions);                  }              }                @Override              public void onScrollStateChanged(RecyclerView recyclerView, int newState) {                  View firstView = recyclerView.getChildAt(0);                  int top = firstView.getTop();                  int topEdge = recyclerView.getPaddingTop();                  //判断RecyclerView 的ItemView是否满屏,如果不满一屏,上拉不会触发加载更多                  boolean isFullScreen = top < topEdge;                    RecyclerView.LayoutManager manager = recyclerView.getLayoutManager();                  int itemCount = manager.getItemCount();                  //因为LoadMore View  是Adapter的一个Item,显示LoadMore 的时候,Item数量+1了,导致 mLastVisibalePosition == itemCount-1                  // 判断两次都成立,因此必须加一个判断条件 !mBaseAdapter.isShowLoadMore()                  if(newState == RecyclerView.SCROLL_STATE_IDLE && mLastVisiblePosition == itemCount-1 && isFullScreen && !mBaseAdapter.isShowLoadMore()){                     //最后一个Item了                     mBaseAdapter.showLoadMore();                     onLoadMore();                  }              }          });          View toolbarView = addToolbar();          if(toolbarView!=null && mToolbarContainer!=null                  ){              mToolbarContainer.addView(toolbarView);          }          onRecyclerViewInitialized();        }        /**       * hide load more progress       */      public void hideLoadMore(){          if(mBaseAdapter!=null){              mBaseAdapter.hideLoadMore();          }      }        /**       * 获取组数最大值       * @param lastPositions       * @return       */      private int findMax(int[] lastPositions) {          int max = lastPositions[0];          for (int value : lastPositions) {              if (value > max) {                  max = value;              }          }          return max;      }        /**       * 设置刷新进度条的颜色       * see{@link SwipeRefreshLayout#setColorSchemeResources(int...)}       * @param colorResIds       */      public void setColorSchemeResources(@ColorRes int... colorResIds){          if(mSwipeRefreshLayout!=null){              mSwipeRefreshLayout.setColorSchemeResources(colorResIds);          }      }        /**       * 设置刷新进度条的颜色       * see{@link SwipeRefreshLayout#setColorSchemeColors(int...)}       * @param colors       */      public void setColorSchemeColors(int... colors){          if(mSwipeRefreshLayout!=null){              mSwipeRefreshLayout.setColorSchemeColors(colors);          }      }        /**       * 设置刷新进度条背景色       *  see{@link SwipeRefreshLayout#setProgressBackgroundColorSchemeResource(int)} (int)}       * @param colorRes       */      public void setProgressBackgroundColorSchemeResource(@ColorRes int colorRes) {           if(mSwipeRefreshLayout!=null){               mSwipeRefreshLayout.setProgressBackgroundColorSchemeResource(colorRes);           }      }        /**       * 设置刷新进度条背景色       *  see{@link SwipeRefreshLayout#setProgressBackgroundColorSchemeColor(int)}       * @param color       */      public void setProgressBackgroundColorSchemeColor(@ColorInt int color) {         if(mSwipeRefreshLayout!=null){             mSwipeRefreshLayout.setProgressBackgroundColorSchemeColor(color);         }      }        /**       * Notify the widget that refresh state has changed. Do not call this when       * refresh is triggered by a swipe gesture.       *       * @param refreshing Whether or not the view should show refresh progress.       */      public void setRefreshing(boolean refreshing){          if(mSwipeRefreshLayout== null){              return;          }          mSwipeRefreshLayout.setRefreshing(refreshing);      }        /**       * 子类可以自己指定Adapter,如果不指定默认RVSimpleAdapter       * @return       */      protected RVSimpleAdapter initAdapter(){          return new RVSimpleAdapter();      }        /**       * 子类自己指定RecyclerView的LayoutManager,如果不指定,默认为LinearLayoutManager,VERTICAL 方向       * @return       */      protected RecyclerView.LayoutManager initLayoutManger(){          LinearLayoutManager manager = new LinearLayoutManager(getContext());          manager.setOrientation(LinearLayoutManager.VERTICAL);          return manager;      }        /**       * 添加TitleBar       * @param       */      public View addToolbar(){        //如果需要Toolbar,子类返回Toolbar View        return null;      }        /**       *RecyclerView 初始化完毕,可以在这个方法里绑定数据       */      public abstract void onRecyclerViewInitialized();        /**       * 下拉刷新       */      public abstract void onPullRefresh();        /**       * 上拉加载更多       */      public abstract void onLoadMore();        /**       *  根据实体生成对应的Cell       * @param list  实体列表       * @return cell列表       */      protected abstract  List<Cell> getCells(List<T> list);    }</code></pre>    <p>AbsBaseFragment,实现了上拉加载和下拉刷新功能,添加Toolbar等,上拉加载可以自定义View,下拉刷新用的是Google的SwipeRefreshLayout。要添加一个列表界面,只需要继承AbsBaseFragment,实现几个抽象方法添加Cell就行了,非常方便。</p>    <h3>用法示例:</h3>    <p>添加一个多Item的列表:</p>    <p>1,创建一个Fragment继承AbsBaseFragment,实现几个方法。</p>    <pre>  <code class="language-java">/**   * Created by zhouwei on 17/2/3.   */    public class HomePageFragment extends AbsBaseFragment<Entry> {      @Override      public void onRecyclerViewInitialized() {         //初始化View和数据加载       }        @Override      public void onPullRefresh() {          //下拉刷新回调        }        @Override      public void onLoadMore() {          //上拉加载回调      }      protected List<Cell> getCells(List<Entry> entries){          //根据实体生成Cell          return null;      }    }</code></pre>    <p>实现上面几个抽象方法,实际上只实现onRecyclerViewInitialized和getCells两个方法就可以实现列表,其它两个方法是下拉刷新和上拉加载的。</p>    <p>2,创建Cell类</p>    <pre>  <code class="language-java">/**   * Created by zhouwei on 17/2/7.   */    public class BannerCell extends RVBaseCell<List<String>> {      public static final int TYPE = 2;      private ConvenientBanner mConvenientBanner;      public BannerCell(List<String> strings) {          super(strings);      }        @Override      public int getItemType() {          return TYPE;      }        @Override      public RVBaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {          return new RVBaseViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.grid_cell_layoout,null));      }        @Override      public void onBindViewHolder(RVBaseViewHolder holder, int position) {         mConvenientBanner = (ConvenientBanner) holder.getView(R.id.banner);          mConvenientBanner.setPages(new CBViewHolderCreator<NetworkImageHolderView>() {              @Override              public NetworkImageHolderView createHolder() {                  return new NetworkImageHolderView();              }          }, mData);          mConvenientBanner.startTurning(2000);      }        @Override      public void releaseResource() {          if(mConvenientBanner!=null){              mConvenientBanner.stopTurning();          }      }        public static class NetworkImageHolderView implements CBPageAdapter.Holder<String>{          private ImageView imageView;          @Override          public View createView(Context context) {              imageView = new ImageView(context);              imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);              return imageView;          }            @Override          public void UpdateUI(Context context, int position, String data) {              ImageLoader.getInstance().displayImage(data,imageView);          }      }  }</code></pre>    <pre>  <code class="language-java">/**   * Created by zhouwei on 17/1/19.   */    public class ImageCell extends RVBaseCell<Entry> {      public static final int TYPE = 1;      public ImageCell(Entry entry) {          super(entry);      }        @Override      public int getItemType() {          return TYPE;      }        @Override      public RVBaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {          return new RVBaseViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.image_cell_layout,null));      }        @Override      public void onBindViewHolder(RVBaseViewHolder holder, int position) {          Picasso.with(holder.getItemView().getContext()).load(mData.imageUrl).into(holder.getImageView(R.id.image));      }    }</code></pre>    <pre>  <code class="language-java">/**   * Created by zhouwei on 17/1/19.   */    public class TextCell extends RVBaseCell<Entry> {      public static final int TYPE = 0;      public TextCell(Entry entry) {          super(entry);      }        @Override      public int getItemType() {          return TYPE;      }        @Override      public RVBaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {          return new RVBaseViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.text_cell_layout,null));      }        @Override      public void onBindViewHolder(RVBaseViewHolder holder, int position) {         holder.setText(R.id.text_content,mData.content);      }  }</code></pre>    <p>上面创建了3个Cell,也就是这个列表包含了3种不同类型的Item。</p>    <p>注意:一个列表内,每个Cell 的TYPE要不相同,也就是getItemType方法的返回值要不同。</p>    <p>3,onRecyclerViewInitialized ,做初始化和加载数据</p>    <pre>  <code class="language-java">@Override      public void onRecyclerViewInitialized() {         //初始化View和数据加载         //设置刷新进度条颜色         setColorSchemeResources(R.color.colorAccent);         loadData();      }        /**       * 模拟从服务器取数据       */      private void loadData(){          View loadingView = LayoutInflater.from(getContext()).inflate(R.layout.manu_loading_layout,null);          mBaseAdapter.showLoading(loadingView);          mRecyclerView.postDelayed(new Runnable() {              @Override              public void run() {                  mBaseAdapter.hideLoading();                  mBaseAdapter.addAll(getCells(mockData()));              }          },2000);      }</code></pre>    <p>4,实现getCells方法,生成Cell</p>    <pre>  <code class="language-java">protected List<Cell> getCells(List<Entry> entries){          //根据实体生成Cell          List<Cell> cells = new ArrayList<>();          cells.add(new BannerCell(Arrays.asList(DataMocker.images)));          for (int i=0;i<entries.size();i++){              Entry entry = entries.get(i);              if(entry.type == Entry.TYPE_IMAGE){                  cells.add(new ImageCell(entry));              }else{                  cells.add(new TextCell(entry));              }          }          return cells;      }</code></pre>    <p>上面根据实体生成不同的Cell。有三种Cell,BannerCell,ImageCell和TextCell。</p>    <p>以上4个步骤就能实现一个界面复杂包含多做Item的列表了效果图如下:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/d70f17edae14913fc150dd874b51b634.gif"></p>    <p style="text-align:center">adapter_cell.gif</p>    <p>HomePageFragment 的完整代码如下:</p>    <pre>  <code class="language-java">/**   * Created by zhouwei on 17/2/3.   */    public class HomePageFragment extends AbsBaseFragment<Entry> {      @Override      public void onRecyclerViewInitialized() {         //初始化View和数据加载         //设置刷新进度条颜色         setColorSchemeResources(R.color.colorAccent);         loadData();      }        @Override      public void onPullRefresh() {          //下拉刷新回调          mRecyclerView.postDelayed(new Runnable() {              @Override              public void run() {                 setRefreshing(false);              }          },2000);      }        @Override      public void onLoadMore() {          //上拉加载回调         loadMore();      }          private void loadMore(){          mRecyclerView.postDelayed(new Runnable() {              @Override              public void run() {                  hideLoadMore();                  mBaseAdapter.addAll(getCells(mockMoreData()));              }          },10000);      }        protected List<Cell> getCells(List<Entry> entries){          //根据实体生成Cell          List<Cell> cells = new ArrayList<>();          cells.add(new BannerCell(Arrays.asList(DataMocker.images)));          for (int i=0;i<entries.size();i++){              Entry entry = entries.get(i);              if(entry.type == Entry.TYPE_IMAGE){                  cells.add(new ImageCell(entry));              }else{                  cells.add(new TextCell(entry));              }          }          return cells;      }          @Override      public View addToolbar() {          View toolbar = LayoutInflater.from(getContext()).inflate(R.layout.title_bar_layout,null);          return toolbar;      }        /**       * 模拟从服务器取数据       */      private void loadData(){          View loadingView = LayoutInflater.from(getContext()).inflate(R.layout.manu_loading_layout,null);          mBaseAdapter.showLoading(loadingView);          mRecyclerView.postDelayed(new Runnable() {              @Override              public void run() {                  mBaseAdapter.hideLoading();                  mBaseAdapter.addAll(getCells(mockData()));              }          },2000);      }  }</code></pre>    <p>Grid 列表和瀑布流列表:</p>    <p>上面演示了添加多Item type 的列表,添加单Item的列表也是一样的,只不过只有一个Cell而已。添加Grid 列表和瀑布流列表差不多的,只是RecylerView 的LayoutManager不同而已。</p>    <p>瀑布流列表示例:</p>    <pre>  <code class="language-java">/**   * Created by zhouwei on 17/2/4.   */    public class DetailFragment extends AbsBaseFragment<DetailEntry> {      @Override      public void onRecyclerViewInitialized() {           mBaseAdapter.setData(getCells(mockStaggerData()));      }        @Override      public void onPullRefresh() {        }        @Override      public void onLoadMore() {        }        @Override      protected RecyclerView.LayoutManager initLayoutManger() {          StaggeredGridLayoutManager layoutManager = new StaggeredGridLayoutManager(2,StaggeredGridLayoutManager.VERTICAL);          return layoutManager;      }        @Override      protected List<Cell> getCells(List<DetailEntry> list) {          List<Cell> cells = new ArrayList<>();          for (int i=0;i<list.size();i++){              cells.add(new DetailCell(list.get(i)));          }          return cells;      }    }</code></pre>    <p>只需要重写initLayoutManager这个方法,返回一个瀑布流的LayoutMannger就可以了。</p>    <p>效果如下:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/fa39d49879198c7bf48d61cdbab326c3.gif"></p>    <p style="text-align:center">stagger_adapter_cell.gif</p>    <h3>其它演示示例:加载更多、Loading View 、Error View ,Empty View</h3>    <p>1,显示LoadMoreView</p>    <p>提供了默认的LoadingView,调用代码如下:</p>    <pre>  <code class="language-java">mBaseAdapter.showLoadMore();</code></pre>    <p>隐藏LoadMore View 调用如下代码:</p>    <pre>  <code class="language-java">if(mBaseAdapter!=null){              mBaseAdapter.hideLoadMore();     }</code></pre>    <p>效果图看上面演示的瀑布流效果图。</p>    <p>2,显示loading View</p>    <p>提供了默认的Loading View,调用代码如下:</p>    <pre>  <code class="language-java">mBaseAdapter.showLoading();</code></pre>    <p>当然也可以自定义Loading View,提供一个布局即可:</p>    <pre>  <code class="language-java">View loadingView = LayoutInflater.from(getContext()).inflate(R.layout.manu_loading_layout,null);   mBaseAdapter.showLoading(loadingView);</code></pre>    <p>效果如下:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/6fe1fe46041eda192d6ac12007e82de4.png"></p>    <p style="text-align:center">loading_view.png</p>    <p>还有一种情况是,顶部有一个固定的HeaderCell,不需要加载数据,显示静态页面,下面加载数据时需要Loading态,Error状态,Empty状态等等。提供如下3个方法:</p>    <ul>     <li> <p>showLoadingKeepCount(int keepCount,int height,View loadingView)</p> <p>列表Loading状态显示的View,保留keepCountg个Item,并指定高度,指定显示的View</p> </li>     <li> <p>showLoadingKeepCount(int keepCount,int height)</p> <p>列表Loading状态显示的View,保留keepCountg个Item,并指定高度(显示的是提供的默认Loading View)</p> </li>     <li> <p>showLoadingKeepCount(int keepCount)</p> <p>显示默认LoadingView</p> </li>    </ul>    <p>使用代码如下:</p>    <pre>  <code class="language-java">View loadingView = LayoutInflater.from(getContext()).inflate(R.layout.manu_loading_layout,null);  mBaseAdapter.showLoadingKeepCount(1,height,loadingView);</code></pre>    <p>效果图如下:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/fc96facecec89fa974f6a5353b010ff2.png"></p>    <p style="text-align:center">loading_view_keep_count.png</p>    <p>隐藏Loading View 调用对应hide 方法:</p>    <pre>  <code class="language-java">mBaseAdapter.hideLoading();</code></pre>    <p>3, Error View 和 Empty View</p>    <p>显示Error View 和Empty View 与Loading View 的显示与隐藏是一样,不在过多讲,直接去看源码,提供了几个方法:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/12e55e45eba135fa22e6554a2bd07555.png"></p>    <p style="text-align:center">error_method.png</p>    <p>效果图:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/9cc04718e40550a8feea1f20ed28bf75.png"></p>    <p style="text-align:center">error_tip.png</p>    <p>Empty View 的显示完全一样,就不再讲了。</p>    <h3>最后</h3>    <p>以上就是对RecyclerView Adapter 的封装和 该库的使用介绍,使用起来非常方便,添加一个列表不再是重复的写Adapter,ViewHolder 等等。添加一个Cell 填充到Adapter 就OK。增加一种Item或者加少一种Item对列表完全没有影响,耦合度几乎为0。</p>    <p> </p>    <p>来自:http://www.jianshu.com/p/727c18f4bf20</p>    <p> </p>