更好用的Adapter For RecyclerView

更好用的Adapter For RecyclerViewXCoreRecyclerAdapter:一种通用的Adapter For RecyclerView背景每当我们使用RecyclerView写一

大家好,欢迎来到IT知识分享网。

XCoreRecyclerAdapter:一种通用的Adapter For RecyclerView

背景

每当我们使用RecyclerView写一个列表的时候,都需要写类似的如下代码:

mTestRv = (RecyclerView) view.findViewById(R.id.test_home_rv);

mTestRecyclerAdapter = new TestRecyclerAdapter(context);

mLinearLayoutManager = new LinearLayoutManager(context);

mTestRv.setLayoutManager(mLinearLayoutManager);

mTestRv.setAdapter(mTestRecyclerAdapter);

那么,我们一般必不可少的是写一个Adapter,比如,为了支持多种类型,我们需要重写getItemViewType、onCreateViewHolder、onBindViewHolder等方法。比如:

public class TestRecyclerAdapter extends RecyclerView.Adapter<BaseViewHolder> {

… @Override

public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

View view = null; switch (viewType) { case Type.TYPE_HEADER:

view = LayoutInflater.from(mContext).inflate(R.layout.card_header,

parent, false); return new HeaderViewHolder(view); case Type.TYPE_HIS_HEAD:

view = LayoutInflater.from(mContext).inflate(R.layout.his_header,

parent, false); return new HeaderHisViewHolder(view);

… default: break;

} return new HeaderViewHolder(new RelativeLayout(mContext));

} @Override

public void onBindViewHolder(ViewHolder holder, int position) { switch (getItemViewType(position)) { case Type.TYPE_HEADER:

HeaderViewHolder headerViewHolder = (HeaderViewHolder) holder;

headerViewHolder.bindView(mDataSet.get(position)); break; case Type.TYPE_HIS_HEAD:

HeaderHisViewHolder headerHisViewHolder = (HeaderHisViewHolder) holder;

headerHisViewHolder.bindView(mDataSet.get(position), mOnHeaderItemClickListener); break;

… default: break;

}

} @Override

public int getItemViewType(int position) {

Data data = mDateSet.get(position);

String type = data.getType(); if(“xxx”.equals(type)){ return Type.TYPE_HEADER;

}else if(“xxxxx”.equals(type)){ return Type.TYPE_HIS_HEAD;

}else if(){

}

}

}

按照上述写法,每当我们需要增加一种类型的时候,都需要修改TestRecyclerAdapter的代码,在onCreateViewHolder等方法中添加对应的代码。后来大家觉得这个挺烦的,然后就把onCreateViewHolder中的switch语句放到工厂类当中,这一定层度上缓解了修改Adapter的频率。那么,我们能不能写一个相对通用的Adapter呢?

封装通用的插件式Adapter

我们希望做到如下目标:

  • 1).Adapter通用化,无需每次新建Adapter

  • 2).Item(Cell)的组件是插件式的,解耦,并可复用

用代码描述为:

//创建通用的Adapter

mXCoreRecyclerAdapter = new XCoreRecyclerAdapter(context); //Adapter注册item组件

mXCoreRecyclerAdapter.registerItemUIComponent(new TodoItemComponent()) .registerItemUIComponent(new TestItemComponent()); //设置数据源,完成展示

mXCoreRecyclerAdapter.setDataSet(List<IDataComponent> dataSet) …

插件式的通用XCoreRecyclerAdapter的原理图如下:

更好用的Adapter For RecyclerView

每当我们需要添加一个新的类型时,只需要一下几步:

  • 1.新建一个TodoItemUIComponent组件,继承自XCoreItemUIComponent

    实现对应的方法;

  • 2.注册新增的组件TodoItemUIComponent

    调用XCoreRecyclerAdapter的registerItemUIComponent方法即可注册。

  • 3.数据源实现IDataComponent接口

    getViewType和组件TodoItemUIComponent的getViewType匹配即可;

这样,每次新增一种新的类型的Item时,无需修改Adapter的代码。并且,Item的组件是可复用的。

那么具体怎么设计的呢?

数据源

首先对数据源进行抽象:在Adapter列表中,需要根据数据源Data的不同类型,选择不同的ViewHolder。所以,数据源必须有一个getType的方法。

/**

* 数据源必须实现的接口

*/

public interface IDataComponent { String getViewType();

}

Item组件 ItemUIComponent

ItemUIComponent组件负责某一类type的管理。为了做到插件式,它必须实现的方法有:

  • onCreateView方法

    该方法是用于生成Item的根View的。当Adapter调用onCreateViewHolder时,该方法会被调用。注意,子View的初始化,不要写在onCreateView中。需要写在onViewCreated方法中。

  • onViewCreated方法

    创建完ItemComponent之后,就会立即回调该方法,View的初始化请写在这里。

  • getViewType方法

    该方法是为了和数据源进行关联的,数据源的getViewType方法和组件的getViewType方法的值一致时,即完成匹配。

  • bindView方法

    该方法会在Adapter回调onBindViewHolder

public class TodoItemComponent extends XCoreItemUIComponent { @Override

public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container) { //TODO 在这里指定item组件的布局

return inflater.inflate(R.layout.todo_item_layout,container,false);

} @Override

public void onViewCreated(View view) { //TODO 在这里写View初始化

view.findViewById();

} @Override

public String getViewType() { //与数据源的getViewType关联

return TodoItemComponent.class.getSimpleName();

} @Override

public void bindView(IXCoreComponent coreComponent,

XCoreRecyclerAdapter coreRecyclerAdapter,

XCoreRecyclerAdapter.IDataComponent data, int pos) { //TODO 在这里写绑定逻辑

}

}

数据源和Item组件都已经定义好,那么,核心的XCoreRecyclerAdapter源码应该怎么做呢?

XCoreRecyclerAdapter源码

package com.github.nuptboyzhb.xcore.adapter;import android.content.Context;import android.support.v7.widget.RecyclerView;import android.text.TextUtils;import android.util.SparseArray;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import com.github.nuptboyzhb.xcore.components.IXCoreComponent;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;/**

* @version mochuan.zhb on 2016/8/9.

* @Author Zheng Haibo

* @Blog github.com/nuptboyzhb

* @Company Alibaba Group

* @Description 通用的Adapter for RecyclerView

*/public class XCoreRecyclerAdapter extends RecyclerView.Adapter<XCoreRecyclerAdapter.CommonViewHolder> { private IXCoreComponent mIXCoreComponent;//外层UI组件

private List<IDataComponent> mDataSet = new ArrayList<IDataComponent>();//数据源

private SparseArray<XCoreItemUIComponent> mConfigurationSparseArray = new SparseArray<XCoreItemUIComponent>();//集合:type对应的Item组件

private Map<String, Integer> mViewTypeMap = new HashMap<String, Integer>();//type的string和int映射

public XCoreRecyclerAdapter() {

} public XCoreRecyclerAdapter(IXCoreComponent mIXCoreComponent) { this.mIXCoreComponent = mIXCoreComponent;

} @Override

public CommonViewHolder onCreateViewHolder(ViewGroup viewGroup, int type) { //根据数据类型获取对应的item组件

XCoreItemUIComponent XCoreItemUIComponent = mConfigurationSparseArray.get(type); if (XCoreItemUIComponent == null) {//如果未获取到,展示空item

return getDefaultViewHolder(viewGroup.getContext());

} try { //使用item组件创建一个新的View

View view = XCoreItemUIComponent.onCreateView(LayoutInflater.from(viewGroup.getContext()), viewGroup); //使用View构建内部的ViewHolder

CommonViewHolder commonViewHolder = new CommonViewHolder(view); //创建一个新的Item组件

XCoreItemUIComponent realItem = XCoreItemUIComponent.getClass().newInstance(); //将创建的View设置到真是的Item组件中

realItem.setItemView(view); //使用内部ViewHolder

commonViewHolder.setXCoreItemUIComponent(realItem); return commonViewHolder;

} catch (Throwable t) {

t.printStackTrace();

} return getDefaultViewHolder(viewGroup.getContext());

} @Override

public void onBindViewHolder(CommonViewHolder baseViewHolder, int pos) {

baseViewHolder.bindView(mIXCoreComponent, this, mDataSet.get(pos), pos);

} @Override

public int getItemViewType(int position) {

IDataComponent item = mDataSet.get(position);

Integer integer = mViewTypeMap.get(item.getViewType()); if (integer == null) { return -1;

} return integer;

} @Override

public int getItemCount() { if (mDataSet != null) { return mDataSet.size();

} return 0;

} /**

* 获取Adapter的数据源

*

* @return

*/

public List<IDataComponent> getDataSet() { return mDataSet;

} /**

* 设置Adapter的数据源

*

* @param dataSet

*/

public void setDataSet(List<IDataComponent> dataSet) { this.mDataSet = dataSet;

notifyDataSetChanged();

} /**

* get the error view holder

*

* @param context

* @return

*/

protected CommonViewHolder getDefaultViewHolder(Context context) { return new CommonViewHolder(new View(context));

} /**

* get the unique int type

*

* @param name

* @return

*/

private int getUniqueIntType(String name) { if (TextUtils.isEmpty(name)) { return -1;

} int type = name.hashCode(); while (true) {

XCoreItemUIComponent old = mConfigurationSparseArray.get(type); if (old != null) {

String oldName = old.getViewType(); if (!name.equals(oldName)) {

type = type + 1;

} else { return type;

}

} else { return type;

}

}

} /**

* 注册Item组件

*

* @param XCoreItemUIComponent

* @return

*/

public XCoreRecyclerAdapter registerItemUIComponent(XCoreItemUIComponent XCoreItemUIComponent) { if (XCoreItemUIComponent == null || TextUtils.isEmpty(XCoreItemUIComponent.getViewType())) { return this;

} int viewTypeInt = getUniqueIntType(XCoreItemUIComponent.getViewType());

mViewTypeMap.put(XCoreItemUIComponent.getViewType(), viewTypeInt);

mConfigurationSparseArray.put(viewTypeInt, XCoreItemUIComponent); return this;

} /**

* 注销配置

*

* @param XCoreItemUIComponent

* @return

*/

public XCoreRecyclerAdapter unregisterItemUIComponent(XCoreItemUIComponent XCoreItemUIComponent) { if (XCoreItemUIComponent == null || TextUtils.isEmpty(XCoreItemUIComponent.getViewType())) { return this;

} int index = mConfigurationSparseArray.indexOfValue(XCoreItemUIComponent); if (index == -1) { return this;

}

mConfigurationSparseArray.remove(index); return this;

} /**

* 数据源必须实现的接口

*/

public interface IDataComponent { String getViewType();

} /**

* 使用CommonViewHolder代理XCoreItemUIComponent组件

*/

public static class CommonViewHolder extends RecyclerView.ViewHolder { private XCoreItemUIComponent XCoreItemUIComponent; public void setXCoreItemUIComponent(XCoreItemUIComponent XCoreItemUIComponent) { this.XCoreItemUIComponent = XCoreItemUIComponent;

} public XCoreItemUIComponent getXCoreItemUIComponent() { return XCoreItemUIComponent;

} public CommonViewHolder(View itemView) { super(itemView);

} public void bindView(IXCoreComponent mIXCoreComponent,

XCoreRecyclerAdapter XCoreRecyclerAdapter,

XCoreRecyclerAdapter.IDataComponent data, int pos) { if (XCoreItemUIComponent == null) { return;

}

XCoreItemUIComponent.bindView(mIXCoreComponent, XCoreRecyclerAdapter, data

, pos);

} public void onViewDetachedFromWindow() { if (XCoreItemUIComponent != null) {

XCoreItemUIComponent.onViewDetachedFromWindow();

}

}

} @Override

public void onViewDetachedFromWindow(CommonViewHolder holder) { super.onViewDetachedFromWindow(holder);

holder.onViewDetachedFromWindow();

}

}

XCoreItemUIComponent源码

package com.github.nuptboyzhb.xcore.adapter;

import android.support.annotation.Nullable;

import android.view.LayoutInflater;

import android.view.View;

import android.view.ViewGroup;

import com.github.nuptboyzhb.xcore.components.IXCoreComponent;

import java.util.ArrayList;

import java.util.HashMap;

import java.util.List;

import java.util.Map;

/**

* @version mochuan.zhb on 2016/8/12.

* @Author Zheng Haibo

* @Blog github.com/nuptboyzhb

* @Company Alibaba Group

* @Description item component 抽象类

*/

public abstract class XCoreItemUIComponent implements IXCoreComponent {

/**

* 创建View *

* @param inflater

* @param container

* @return

*/

public abstract View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container);

/**

* 在此做View的初始化操作 *

* @param view

*/

public abstract void onViewCreated(View view);

/**

* item组件支持的ViewType,与IDataComponent的getViewType对应 *

* @return

*/

public abstract String getViewType();

/**

* 绑定数据-频繁回调 *

* @param coreComponent 外出UI组件

* @param coreRecyclerAdapter Adapter

* @param data 对应的数据源

* @param pos item所在列表的位置

*/

public abstract void bindView(IXCoreComponent coreComponent,

XCoreRecyclerAdapter coreRecyclerAdapter,

XCoreRecyclerAdapter.IDataComponent data,

int pos);

/**

* item组件销毁时调用 */

public abstract void onViewDetachedFromWindow();

//必须有无参数的构造函数

public View itemView;

public void setItemView(View itemView) {

this.itemView = itemView;

onViewCreated(itemView);

}

}

后续

本篇博客主要是介绍通用的XCoreRecyclerAdapter引擎,极大提高了Adapter的复用率,让开发集中把精力集中在必要的业务代码上,提高开发效率。另外,与XCoreRecyclerAdapter引擎相配套的还有UI组件化、数据控制框架XCoreRedux、数据绑定等。请参考下一遍博客:《Android Redux实践与UI组件化:XCoreRedux框架》(ing…)

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/59295.html

(0)

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信