RecyclerViewHelper原码解析
来源:互联网 发布:windows 确认证书 编辑:程序博客网 时间:2024/05/18 00:00
RecyclerViewHelper是RecyclerView 的工具类,可以更方便的实现 Adapter,item 点击事件,更快的实现加载提示,分页加载。
首先我们来看看demo
先是MainActivity
private RecyclerView list_container; private List<String> dataList; private ListAdapter listAdapter; private RecyclerViewHelper recyclerViewHelper; private int loadCount = 0;定义了五个变量,分别是 RecyclerView ,String泛型的List,自定义List适配器,本文所提及的Helper,和一个计数器loadCount
我们先看看适配器ListAdapter
public class ListAdapter extends CommonAdapter<String> { public ListAdapter(@NonNull List<String> dataList) { super(dataList, R.layout.item_list); } @Override public void convert(BaseViewHolder holder, String s, int position) { }}代码很简单,继承了一个CommonAdapter,设定了一个item布局,但需要注意的是这里所继承的CommonAdapter是重写的
我们来看看源码
public abstract class CommonAdapter<T> extends RecyclerView.Adapter<BaseViewHolder>这是一个抽象类继承于RecyclerView的Adapter
我们来看看整个类的代码
public abstract class CommonAdapter<T> extends RecyclerView.Adapter<BaseViewHolder> { private List<T> dataList; //T泛型的List private int itemLayoutId = 0; //item布局id public CommonAdapter(@NonNull List<T> dataList, int itemLayoutId) { //构造方法,这里的NonNull指的是不为null的附加条件 this.dataList = dataList; this.itemLayoutId = itemLayoutId; } @Override public BaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { //Holder的onCreate方法,绑定了item布局id BaseViewHolder holder = new BaseViewHolder(getLayoutView(parent, itemLayoutId)); setListener(holder); return holder; } @Override public void onBindViewHolder(BaseViewHolder holder, int position) { //绑定Holder convert(holder, dataList.get(position), holder.getAdapterPosition()); } @Override public int getItemCount() { //获取item的数目 return dataList.size(); } public View getLayoutView(ViewGroup parent, int layoutId) { //返回LayoutView return LayoutInflater.from(parent.getContext()).inflate(layoutId, parent, false); } /** * 设置 * * @param viewHolder */ private void setListener(final BaseViewHolder viewHolder) { //设置监听,监听点击事件 viewHolder.getConvertView().setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (onItemClickListener != null) { int position = viewHolder.getAdapterPosition(); //获取position onItemClickListener.onItemClick(v, viewHolder, position); } } }); } public abstract void convert(BaseViewHolder holder, T t, int position); //抽象的convert方法//点击监听部分源代码 private OnItemClickListener onItemClickListener; public interface OnItemClickListener { //监听器接口 void onItemClick(View view, BaseViewHolder holder, int position); } public void setOnItemClickListener(OnItemClickListener onItemClickListener) { this.onItemClickListener = onItemClickListener; }}总而言之,CommonAdapter是夹带设置监听点击事件的Adapter,以前的话监听点击是需要我们自己手动添加监听在Adapter中,有了这个之后变得简单了。
需要注意的是这里的BaseViewHolder也是重写的
贴一下代码
public class BaseViewHolder extends RecyclerView.ViewHolder { private final SparseArray<View> views; //SparseArray,之前的文章有提及,一种效率高的Array,这里使用View泛型 public View convertView; public BaseViewHolder(View itemView) { super(itemView); this.views = new SparseArray<>(); convertView = itemView; } public View getConvertView() { return convertView; } public <T extends View> T getView(int viewId) {//返回相应泛型的View View view = views.get(viewId); if (view == null) { view = convertView.findViewById(viewId); views.put(viewId, view); } return (T) view; }....}下面给出MainActvity的代码
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main);//设置布局 list_container = (RecyclerView) findViewById(R.id.list_container); //实例化RecyclerView dataList = new ArrayList<>(); listAdapter = new ListAdapter(dataList); //设置适配器 //使用helper实现分页加载和加载的Tips recyclerViewHelper = new RecyclerViewHelper(list_container, listAdapter); //设置没有数据的Tips recyclerViewHelper.setTipsEmptyView(R.layout.view_data_empty); //设置加载中的Tips recyclerViewHelper.setTipsLoadingView(R.layout.view_data_loading); //设置加载失败的Tips recyclerViewHelper.setTipsErrorView(R.layout.view_data_error); //加载失败,没有数据时Tips的接口 recyclerViewHelper.setTipsListener(new TipsListener() { @Override public void retry() { initData(); } }); //设置header// recyclerViewHelper.setHeaderView(R.layout.view_header); //加载更多的接口 recyclerViewHelper.setLoadMoreListener(new LoadMoreListener() { @Override public void loadMore() { loadNext(); } }); initData();
}给出loadNext和initData方法的代码
private void loadNext() { new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(800); } catch (InterruptedException e) { e.printStackTrace(); } runOnUiThread(new Runnable() { @Override public void run() { if (loadCount % 2 != 0) { //分页数据加载失败 recyclerViewHelper.loadMoreError(); } else if (loadCount < 7) { for (int i = 0; i < 10; i++) { dataList.add(String.valueOf(i)); } //分页数据加载成功,还有下一页 recyclerViewHelper.loadMoreFinish(true); } else { //分页数据加载成功,没有更多。即全部加载完成 recyclerViewHelper.loadMoreFinish(false); } loadCount++; } }); } }).start(); } private void initData() { dataList.clear(); new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } runOnUiThread(new Runnable() { @Override public void run() { if (loadCount == 0) { //首次加载数据成功 recyclerViewHelper.loadTipsComplete(); } else if (loadCount == 1) { //首次数据记载失败 recyclerViewHelper.loadTipsError(); } else { for (int i = 0; i < 10; i++) { dataList.add(String.valueOf(i)); } recyclerViewHelper.loadTipsComplete(); } loadCount++; } }); } }).start(); }到此,已基本实现RecyclerView适配器的加载,可以看出这个Helper可以帮助我们更好的实现Adapter的加载,各种加载提示和分页加载
接下来我们来看看这个Helper的源码
public class RecyclerViewHelper { private RecyclerView recyclerView; //RecyclerView private RecyclerView.LayoutManager layoutManager; //布局管理器 private RecyclerView.Adapter adapter; //适配器 private HelperAdapter helperAdapter; //自定义适配器 private LoadMoreListener loadMoreListener; //自定义监听器 private boolean hasMore = true; //是否有更多 private boolean isLoading = false; //是否正在加载
//构造方法1 public RecyclerViewHelper(RecyclerView recyclerView, RecyclerView.Adapter adapter) { this(recyclerView, null, adapter); } //构造方法2 public RecyclerViewHelper(@NonNull RecyclerView recyclerView, RecyclerView.LayoutManager layoutManager, @NonNull RecyclerView.Adapter adapter) { this.recyclerView = recyclerView; this.layoutManager = layoutManager; this.adapter = adapter; if (layoutManager == null) {//不传layoutManager默认为LinearLayoutManager this.layoutManager = new LinearLayoutManager(recyclerView.getContext()); } else { this.layoutManager = layoutManager; } setup(); } private void setup() { recyclerView.setLayoutManager(layoutManager); recyclerView.setHasFixedSize(true);//设置item固定宽高可提高性能 helperAdapter = new HelperAdapter(adapter); recyclerView.setAdapter(helperAdapter); //监听RecyclerView的滚动 recyclerView.addOnScrollListener(new RecyclerViewScrollListener() { @Override public void loadMore(RecyclerView recyclerView) { if (isLoading || adapter.getItemCount() == 0) return; if (hasMore) {//设置footer为加载中... if (loadMoreListener != null) { LoadMoreUtil.updateState(recyclerView, LoadMoreView.State.LOADING, null); isLoading = true; loadMoreListener.loadMore(); } } else {//设置footer为加载完成 LoadMoreUtil.updateState(recyclerView, LoadMoreView.State.NO_MORE, null); } } }); } //设置tips为空的view public RecyclerViewHelper setTipsEmptyView(int layoutId) { if (helperAdapter != null) { helperAdapter.setTipsEmptyView(layoutId); } return this; } //设置正在加载的View public RecyclerViewHelper setTipsLoadingView(int layoutId) { if (helperAdapter != null) { helperAdapter.setTipsLoadingView(layoutId); } return this; } //设置错误提示的View public RecyclerViewHelper setTipsErrorView(int layoutId) { if (helperAdapter != null) { helperAdapter.setTipsErrorView(layoutId); } return this; } //设置顶部View public RecyclerViewHelper setHeaderView(int layoutId) { if (helperAdapter != null) { helperAdapter.setHeaderView(layoutId); } return this; } //加载完成 public void loadTipsComplete() { if (helperAdapter != null) { helperAdapter.loadTipsComplete(); } } /** * 加载失败 */ public void loadTipsError() { if (helperAdapter != null) { helperAdapter.loadTipsError(); } } //加载更多完成 public void loadMoreFinish(boolean hasMore) { this.hasMore = hasMore; this.isLoading = false; if (!hasMore) { LoadMoreUtil.updateState(recyclerView, LoadMoreView.State.NO_MORE, null); } if (helperAdapter != null) { helperAdapter.notifyDataSetChanged(); //设置改变 } } public void loadMoreError() {//设置footer为加载失败 this.hasMore = true; this.isLoading = false; LoadMoreUtil.updateState(recyclerView, LoadMoreView.State.ERROR, new View.OnClickListener() { @Override public void onClick(View v) { LoadMoreUtil.updateState(recyclerView, LoadMoreView.State.LOADING, null); if (loadMoreListener != null) { loadMoreListener.loadMore(); } } }); } public void setLoadMoreListener(LoadMoreListener loadMoreListener) { this.loadMoreListener = loadMoreListener; } //设置监听 public void setTipsListener(TipsListener tipsListener) { if (helperAdapter != null) { helperAdapter.setTipsListener(tipsListener); } }}可以看出添加了很多提示方面的View
我们来看一看HelperAdapter
public class HelperAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> { //继承于RecyclerView的Adapter泛型是ViewHolder private static final String TAG = HelperAdapter.class.getSimpleName(); //设置各情况的标志码 public static final int HEADER_VIEW = 0x00000111; public static final int FOOTER_VIEW = 0x00000222; public static final int LOADING_VIEW = 0x00000333; public static final int EMPTY_VIEW = 0x00000444; public static final int ERROR_VIEW = 0x00000555; /** * 第一次加载提示状态 */ public enum Tips { LOADING, EMPTY, ERROR, NORMAL } private Tips tips = Tips.LOADING; //各类Tips布局ID private int headerLayoutId = 0; private int emptyLayoutId = 0; private int loadingLayoutId = 0; private int errorLayoutId = 0;
//footerView private View footerView; //设置适配器 private final RecyclerView.Adapter<RecyclerView.ViewHolder> itemAdapter; public HelperAdapter(@NonNull RecyclerView.Adapter itemAdapter) { this.itemAdapter = itemAdapter; } /** * 添加Header * * @param headerLayout */ public void setHeaderView(int headerLayout) { this.headerLayoutId = headerLayout; } /** * 添加Footer * * @param footerView */ public void setFooterView(View footerView) { this.footerView = footerView; } public View getFooterView() { return footerView; } /** * 设置空数据显示view * * @param emptyLayout */ public void setTipsEmptyView(int emptyLayout) { this.emptyLayoutId = emptyLayout; } /** * 设置第一次加载时的view * * @param loadingLayout */ public void setTipsLoadingView(int loadingLayout) { this.loadingLayoutId = loadingLayout; } /** * 设置第一次加载错误view * * @param errorLayout */ public void setTipsErrorView(int errorLayout) { this.errorLayoutId = errorLayout; } /** * 加载完成 */ public void loadTipsComplete() { if (itemAdapter.getItemCount() > 0) { tips = Tips.NORMAL; } else { tips = Tips.EMPTY; } notifyDataSetChanged(); } /** * 加载失败 */ public void loadTipsError() { if (itemAdapter.getItemCount() == 0) { tips = Tips.ERROR; } notifyDataSetChanged(); } /** * 第一次加载重试 */ public void loadTipsRetry() { if (itemAdapter.getItemCount() == 0) { tips = Tips.LOADING; } notifyDataSetChanged(); } private int getHeaderViewCount() { return getViewCount(headerLayoutId); } private int getFooterViewCount() { return footerView == null ? 0 : 1; } private int getEmptyViewCount() { return getViewCount(emptyLayoutId); } private int getLoadingViewCount() { return getViewCount(loadingLayoutId); } private int getErrorViewCount() { return getViewCount(errorLayoutId); } private int getViewCount(int layoutId) { return layoutId > 0 ? 1 : 0; } public View getLayoutView(ViewGroup parent, int layoutId) { return LayoutInflater.from(parent.getContext()).inflate(layoutId, parent, false); } /** * 没有数据的view显示逻辑 * * @return */ public int getEmptyViewType() { if (tips == Tips.LOADING && getLoadingViewCount() > 0) { return LOADING_VIEW; } else if (tips == Tips.ERROR && getErrorViewCount() > 0) { return ERROR_VIEW; } else { return EMPTY_VIEW; } } /** * 获取显示类型 * * @param position * @return */ @Override public int getItemViewType(int position) { if (getHeaderViewCount() == 0) { if (itemAdapter.getItemCount() == 0 && getEmptyViewCount() > 0) { return getEmptyViewType(); } } else { if (position == 0) { return HEADER_VIEW; } else if (position == 1 && itemAdapter.getItemCount() == 0 && getEmptyViewCount() > 0) { return getEmptyViewType(); } } if (position >= (getHeaderViewCount() + itemAdapter.getItemCount())) { return FOOTER_VIEW; } return super.getItemViewType(position - getHeaderViewCount()); } /** * 加载holder显示布局 * * @param parent * @param viewType * @return */ @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { if (viewType == LOADING_VIEW) { return new BaseViewHolder(getLayoutView(parent, loadingLayoutId)); } else if (viewType == ERROR_VIEW) { BaseViewHolder holder = new BaseViewHolder(getLayoutView(parent, errorLayoutId)); if (tipsListener != null) { holder.getConvertView().setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { loadTipsRetry(); tipsListener.retry(); } }); } return holder; } else if (viewType == EMPTY_VIEW) { BaseViewHolder holder = new BaseViewHolder(getLayoutView(parent, emptyLayoutId)); if (tipsListener != null) { holder.getConvertView().setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { loadTipsRetry(); tipsListener.retry(); } }); } return holder; } else if (viewType == HEADER_VIEW) { return new BaseViewHolder(getLayoutView(parent, headerLayoutId)); } else if (viewType == FOOTER_VIEW) { return new BaseViewHolder(footerView); } else { return itemAdapter.onCreateViewHolder(parent, viewType); } } /** * 将数据绑定到布局上 * * @param holder * @param position */ @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { int headerCount = getHeaderViewCount(); if (itemAdapter.getItemCount() > 0 && position >= headerCount && position < headerCount + itemAdapter.getItemCount()) { itemAdapter.onBindViewHolder(holder, position - headerCount); } else { ViewGroup.LayoutParams layoutParams = holder.itemView.getLayoutParams(); if (layoutParams instanceof StaggeredGridLayoutManager.LayoutParams) { ((StaggeredGridLayoutManager.LayoutParams) layoutParams).setFullSpan(true); } } } @Override public int getItemCount() { if (itemAdapter.getItemCount() == 0) {//没有数据,只显示header+emptyView return getHeaderViewCount() + getEmptyViewCount(); } else {//有数据不显示emptyView return getHeaderViewCount() + getFooterViewCount() + itemAdapter.getItemCount(); } } private TipsListener tipsListener; public void setTipsListener(TipsListener tipsListener) { this.tipsListener = tipsListener; }}
各部分监听器就不一一列出了,通过对源码的剖析,可以看出Helper实际上改添了许多关于Tips的状态View
同时也简化了Adapter中的item点击事件监听,使我们可以更好地去处理点击事件,关于RecyclerViewHelper就到这里了.
0 0
- RecyclerViewHelper原码解析
- ConcurrentSkipListMap原码解析
- ConcurrentLinkedQueue原码解析
- Gilde原码解析
- C++ 原码、补码和反码解析
- 【原】javascript prototype 解析
- (原)TouchXML解析
- (原)super.paintComponent解析
- 原码
- 原码
- 将Html原码解析成IHTMLDocumet对象,然后使用DOMNode将html显示成一棵树
- 将Html原码解析成IHTMLDocumet对象,然后使用DOMNode将html显示成一棵树
- [原]HTML解析器的项目(1)
- void和void指针解析(原)
- JAVA并发API源码解析:原子类
- 原生态动作解析和Linkify介绍
- 利用原生态PHP 解析Execl
- NOIP原题----传纸条解析
- 2017.01.08 学习日记-职责链模式
- 有容乃大之Java集合,为你量身做嫁衣
- Web前端面试基础知识(一)
- jQuery_基本过滤选择器
- jsp生成验证码
- RecyclerViewHelper原码解析
- vsftpd控制用户禁止访问上级目录 只能访问自己目录
- 让你高效工作的六大Windows应用
- HTML5画布Canvas文本填充、线段属性、裁剪、透明度与像素合并方式
- Codeforces 545C Woodcutters【dp】
- 指针的指针
- CentOS7 安装cobbler自动部署ubuntu
- 2.Nodejs入门-----模块
- 信息: validateJarFile – jar not loaded. See Servlet Spec 2.3, section 9.7.2. Offending class: javax/se