今天看见一篇文章,讲到了RecyclerView一些关于加载多种布局样式时通常用法存在的一些问题,下面是文章地址:http://www.jianshu.com/p/c6a44e18badb 这里先看一下通常大多数人的用法,如下:

package com.jason.recycleview.lylrecycleviewadpdemo;
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.ViewGroup;
public class MyAdpter extends RecyclerView.Adapter {private int type1 = 1;private int type2 = 2;private Context mContext;private List<Data> mList;public MyAdpter(Context con, List<Data> list) {this.mContext = con;this.mList = list;}@Overridepublic int getItemViewType(int position) {if (position == 0)return type1;if (position == 1)return type2;return super.getItemViewType(position);}@Overridepublic RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {if (viewType == type1) {return new ViewHolder1();} else if (viewType == type2) {return new ViewHolder2();}return new ViewHolder3();}@Overridepublic void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {if (holder instanceof ViewHolder1) {.....}else if(holder instanceof ViewHolder2){.....}else if(holder instanceof ViewHolder3){.....}}@Overridepublic int getItemCount() {return mList.size();}
}

据文章上说的这样写存在三种弊端:

1. 类型检查与类型转型,由于在onCreateViewHolder根据不同类型创建了不同的ViewHolder,所以在onBindViewHolder需要针对不同类型的ViewHolder进行数据绑定与逻辑处理,这导致需要通过instanceof对ViewHolder进行类型检查与类型转型。引用文章上的一句话:
[译]关于Android Adapter,你的实现方式可能一直都有问题中是这样说的

许多年前,我在我的显示器上贴了许多的名言。其中的一个来自 Scott Meyers 写的《Effective C++》 这本书(最好的IT书籍之一),它是这么说的:
不管什么时候,只要你发现自己写的代码类似于 “ if the object is of type T1, then do something, but if it’s of type T2, then do something else ”,就给自己一耳光。

2. 我们的这种写法已经违背了 SOLID 原则中的“开闭准则”。即“对扩展开放,对修改封闭。当我们有新的布局需要添加进来时我们需要在原来的Adpter中添加type标记,要在getItemViewType()方法中添加兼容,要在onCreateViewHolder()、onBindViewHolder()中添加新的if、else处理。

3. 增加了日后的维护成本。随着我们布局的不断增加,我们的Adpter会变得越来越庞大。

针对上边的三个问题,网上已经有大牛进行了相关优化,在此膜拜一下,表示一下感谢,我也自己写了一下代码,后边会附上代码的下载地址,那么下边看一下是怎么进行的优化吧。

先看一下代码:


对所有与列表相关的Model 层数据进行抽象封装(BaseValue),当我们在初始化数据源时就能以List<BaseValue>的形式将不同类型的Model集合在列表中;

将列表类型判断的相关代码抽取到ViewTypeFactory中,同时所有列表类型对应的布局资源都在这个类中进行管理维护,增强了扩展性与可维护性;

这里用到了设计模式中的访问者设计模式,不懂的同学可以先去了解一下相关知识,说一下这里的应用:我们可以在我们的Apdter中实例化一个BaseViewTypeFactory对象,通过获取数据源中对应的model类型调用自己的getLayoutId()方法传入我们的BaseViewTypeFactory对象,看代码可以知道在我们的model实现类的getLayoutId()方法中传入的ViewTypeFactory又调用的相应的type()方法,传入了个自对应的model类型,看Factory实现类中根据不同model重载了相应的type()方法,返回的是model对应的布局的.xml文件在R文件中的id,也就是说在getViewItemType()方法中经过这一系列的调用以后最终返回的为对应的layoutId;及在MyAdpter的OnCreatViewHolder(ViewGrop parent,int viewType)中第二个参数不再是我们自己定义的了,而是当前想要生成的ViewHolder中绑定View的LayoutId;看下面MyAdpter中代码:

现在我们可以直接用viewType创建itemView,但是,itemView创建之后,还是需要进行类型判断,创建不同的ViewHolder,那我们来继续处理,我们将RecyclerView.ViewHolder进行抽象,每一种布局对应一个自己的ViewHolder,下面看代码实现:

public abstract class BaseViewHolder<T> extends RecyclerView.ViewHolder {private SparseArray<View> mArray;private View mView;public BaseViewHolder(View itemView) {super(itemView);this.mView = itemView;mArray = new SparseArray<>();}public View getView(int resId) {View view = mArray.get(resId);if (view == null) {view = mView.findViewById(resId);mArray.put(resId, view);}return view;}public abstract void setUpView(T modle,int position,MyAdpter adpter);}
public class ViewHolderOne extends BaseViewHolder<Value1> {public ViewHolderOne(View itemView) {super(itemView);}@Overridepublic void setUpView(final Value1 modle, int position, MyAdpter adpter) {final TextView tv = (TextView) getView(R.id.tv1);tv.setText(modle.getName());tv.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Toast.makeText(tv.getContext(), modle.getName(), Toast.LENGTH_SHORT).show();}});}
}
public class ViewHolderTwo extends BaseViewHolder<Value2> {public ViewHolderTwo(View itemView) {super(itemView);}@Overridepublic void setUpView(Value2 modle, int position, MyAdpter adpter) {TextView tv= (TextView) getView(R.id.tv2);tv.setText(modle.getAddress());}
}

我们继承RecyclerView.ViewHolder做扩展,保存item对应生成的View,通过一个getView()方法用SparseArray做我们要操作的子View的缓存,并且拿到相应的View;这个getView方法是供子类调用的;setUpView()抽象方法子类实现操作自己对应的子View。

定义好了我们的每一种item对应的ViewHolder后,再回到我们的BaseViewTypeFactory

基类添加一个抽象的onCreatViewHolder()方法,ViewTypeFactory类中实现,看下边代码:

public interface BaseViewTypeFactory {int type(Value1 type);int type(Value2 type);int type(Value3 type);BaseViewHolder creatViewHolder(View v,int viewType);
}
public class ViewTypeFactory implements BaseViewTypeFactory {private final int oneId = R.layout.viewtype1;private final int twoId = R.layout.viewtype2;private final int threeId = R.layout.viewtype3;@Overridepublic int type(Value1 type) {return oneId;}@Overridepublic int type(Value2 type) {return twoId;}@Overridepublic int type(Value3 type) {return threeId;}@Overridepublic BaseViewHolder creatViewHolder(View v, int viewType) {BaseViewHolder mv = null;if (viewType == oneId)mv = new ViewHolderOne(v);else if (viewType == twoId)mv = new ViewHolderTwo(v);else if (viewType == threeId)mv = new ViewHolderThree(v);return mv;}
}

这样处理好以后我们就可以在我们adpter类中的onCreatViewHolder()方法中通过我们已经实例好的factory类进行ViewHolder的初始化了看代码:

@Override
public BaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {View v = View.inflate(parent.getContext(), viewType, null);return mFactory.creatViewHolder(v, viewType);
}

分析一下这段代码,首先通过viewType生成View,然后调用creatViewHolder()方法,在方法里根据不同的viewType生成对应的ViewHolder返回;这样一来我们将判断移出了Adpter类,到这里我们的onCreatViewHolder()方法就优化完了,就两行代码,生成View,调用creatViewHolder()生成ViewHolder。是不是感觉Adpter中清新了不少。

然后就是onBindViewHolder()方法,这就简单了,还是看代码:

@Override
public void onBindViewHolder(BaseViewHolder holder, int position) {holder.setUpView(mList.get(position), position, this);}

就一行代码,因为我们在每一个ViewHolder中实现了自己的setUpView()方法,先拿一个看一下:

@Override
public void setUpView(final Value1 modle, int position, MyAdpter adpter) {final TextView tv = (TextView) getView(R.id.tv1);tv.setText(modle.getName());tv.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Toast.makeText(tv.getContext(), modle.getName(), Toast.LENGTH_SHORT).show();}});
}

这是ViewHolder1中的setUpView实现,分析一下:我们在Adpter中的数据源中拿到model与对应的position位置信息,调用setUpView(),在ViewHolder1中通过父类中的getView()方法得到要操作的子View,从model中得到值进行操作。

到目前为止我们的多布局RecyclerView就优化完了,看一下我们的Adpter是不是很清晰:

@Override
public int getItemViewType(int position) {return mList.get(position).getLayoutId(mFactory);
}@Override
public BaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {View v = View.inflate(parent.getContext(), viewType, null);return mFactory.creatViewHolder(v, viewType);
}@Override
public void onBindViewHolder(BaseViewHolder holder, int position) {holder.setUpView(mList.get(position), position, this);}

下面我们把我们activity中的代码与Adpter中代码也附在下边,布局文件没什么好说的,就是一个RecyclerView,没什么特殊的:

public class MainActivity extends AppCompatActivity {private RecyclerView recyclerview;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);recyclerview = (RecyclerView) findViewById(R.id.recyclerview);recyclerview.setLayoutManager(new LinearLayoutManager(this));recyclerview.setAdapter(new MyAdpter(this));}
}
public class MyAdpter extends RecyclerView.Adapter<BaseViewHolder> {private Context mContext;private List<BaseValue> mList;private BaseViewTypeFactory mFactory;public MyAdpter(Context con) {this.mContext = con;mFactory = new ViewTypeFactory();mList = new ArrayList<>();mList.add(new Value1("刘大"));mList.add(new Value3("8"));mList.add(new Value1("王二"));mList.add(new Value1("张三"));mList.add(new Value2("北京"));mList.add(new Value3("11"));mList.add(new Value1("李四"));mList.add(new Value2("上海"));mList.add(new Value1("陈五"));mList.add(new Value3("32"));mList.add(new Value1("周六"));mList.add(new Value2("深圳"));mList.add(new Value1("小明"));mList.add(new Value1("小光"));mList.add(new Value1("小红"));mList.add(new Value3("48"));mList.add(new Value2("天津"));mList.add(new Value2("广州"));}@Overridepublic int getItemViewType(int position) {return mList.get(position).getLayoutId(mFactory);}@Overridepublic BaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {View v = View.inflate(parent.getContext(), viewType, null);return mFactory.creatViewHolder(v, viewType);}@Overridepublic void onBindViewHolder(BaseViewHolder holder, int position) {holder.setUpView(mList.get(position), position, this);}@Overridepublic int getItemCount() {return mList.size();}
}

我们在adpter创建的时候载入了不同类型的数据,下边看一下运行结果:

当我们有新的类型布局进来后,看看我们需要改哪些地方:

1.新建对应model。

2.做Factory兼容。

3.新建新的ViewHolder,实现setUpView()方法就行了。

是不是很简单,我们的Adpter不用动了,是不是扩展性比原来好多了,而且没有了类型的对比转换,维护性也好了,不用管Adpter了,只需做以上三步,就完成了我们新类型布局的添加。好的,这篇文章就写到这里,如果你感觉说的不是很清楚,可以下载源码阅读源码,希望对你有所帮助!

这里附上Demo的下载地址:http://download.csdn.net/detail/liuyonglei1314/973648

RecyclerView多种布局封装优化(雷惊风)相关推荐

  1. Android签名机制及PMS中校验流程(雷惊风)

    @Android签名机制及PMS中校验流程(雷惊风) 网上看到一篇比较好的关于Android签名的文章,但是文章链接不安全,不知道哪天会不会找不到了,而且需要关注才能查看完整版,所以在这里记录一下,原 ...

  2. Android深入源代码分析理解Aidl总体调用流程(雷惊风)

    2017年開始上班的第一天.老不想工作了,假期感觉还没開始就已经结束了,唉,时间就是这样,新的一年開始了,尽管非常不想干正事,没办法,必须干起来.由于后边的路还非常长,距离六十岁还非常远. 刚上班也没 ...

  3. RecyclerView多布局的简单使用

    RecyclerView多布局的简单 RecyclerView 是在Android5.0之后推出的,是一个比ListView更加灵活更加高效的适配器类型控件.但是RecyclerView不同于其他类型 ...

  4. RecyclerView显示加载多种布局的原理

    RecyclerView是对ListView的封装,所以ListView上能用的方法对RecyclerView同样适用,并且会更简单 在实际开发中,我们可能需要一个列表,显示多种布局,getItemV ...

  5. Android开发——布局性能优化的一些技巧(一)

    0. 前言 上一篇我们分析了为什么LinearLayout会比RelativeLayout性能更高,意义在于分析了这两种布局的实现源码,算是对一个小结论的证明过程,但是对布局性能的优化效果,对这两种布 ...

  6. 【Android 性能优化】布局渲染优化 ( CPU 渲染优化 | 减少布局的嵌套 | 测量布局绘制时间 | OnFrameMetricsAvailableListener | 布局渲染优化总结 )

    文章目录 一. 减少布局嵌套 二. 布局渲染时间测量 1. FrameMetrics 使用流程 2. FrameMetrics 参数解析 3. FrameMetrics 代码示例 三. 布局渲染优化总 ...

  7. 多种方法巧妙优化数据库

    多种方法巧妙优化数据库 日期:2011/12/24 16:18:01  来源:本站 点击率:330 我要评论(0)字号:T T T        1.没有索引或者没有用到索引(这是查询慢最常见的问题, ...

  8. RecyclerView Adapter 优雅封装搞定所有列表

    转载自: 依然范特稀西 RecycleView加载列表,封装Adapter,快速高效的添加一个列表(包括单 Item 列表和多item列表). 理念 1, 构造一个通用的Adapter模版,避免每添加 ...

  9. RecyclerView花样布局

    目录: 1.什么是花样布局? 2.实现原理与要点分析 3.RecyclerView多类型item布局实现分类电影展示 1.什么是花样布局?     花样布局也就是我们经常说的多布局,一个Recycle ...

  10. 页面布局让footer居页面底部_网站各页面该如何布局关键词优化提升排名?

    在网站优化中,最值得关注的一个事情就是关键词的布局,因为关键词的布局直接影响着网站的排名.那么怎样布局关键词才能提高页面和关键词的相关性,并提高网站排名呢?下面一起来看看. 一.利用HTML标签布局关 ...

最新文章

  1. SAP Spartacus Theme 设置
  2. VMware Workstation Pro 无法在Windows 上运行的 解决办法
  3. boost asio io_service与 strand 分析
  4. java 优势论文_【是时候升级java11了】 jdk11优势和jdk选择
  5. 语音识别从菜鸟到入门必看的参考书目
  6. python中几个常用的算术函数
  7. ASP.NET 中的 SQL Server 应用服务数据库角色和视图
  8. 移动短信回执怎么开通_微信短视频直播怎么做?
  9. tensorflow两种padding方式
  10. C语言判断一个数是否为素数
  11. libmodbus 开发说明
  12. 相机变换AND正交投影AND透视投影
  13. 微博营销推广策略分析
  14. 一文带你明白什么是浏览器插件?
  15. 【纯干货】Vue仿蘑菇街商城项目(vue+koa+mongodb)
  16. 【b302】侦探推理
  17. PS练习2——相扣的五环
  18. CString类详细介绍
  19. 2. vibrate-arch
  20. 【Android】Dagger2

热门文章

  1. 打乱魔方软件_家里魔方吃灰了?这三款魔方App教你轻松上手
  2. c# 讯飞语音 sdk
  3. JavaScript数组扁平化
  4. 计算机应用能力考试ppt2003,全国专业技术人员计算机应用能力考试_PPT_2003_题库版.docx...
  5. CSS 滚动条,浮动问题,图片bug
  6. Machine Learning读书会,面试算法讲座,创业活动,算法班(历届汇总)
  7. 这样处理,Java中的注释代码也会执行
  8. D3.jsV5入门教程
  9. IT“茫一代”转型记:创业维艰 苦乐皆有
  10. linux卷空间不足问题 gparted工具重新分配根分区空间