同时通过封装来使复杂列表的性能得到一定的保

接着上篇,这里想分享ListAdapter、RecyclerView的封装。众所周知,ListAdapter以及RecyclerView都是列表控件,Google更推荐大家使用RecyclerView。关于RecyclerView的基本使用,不在本篇的讨论范围内。

   最近优化了项目里的列表展示,顺便对RecyclerView的使用做了重新的封装,目的是当列表的需求比较复杂的时候,依然能够保持逻辑的清晰和解耦,同时通过封装来使复杂列表的性能得到一定的保证。

首先介绍下RecyclerView,RecyclerView相比ListView增加了很多新特性:

ListAdapter作为ListView的数据适配器,为ListView提供数据源。在我们的频繁使用中,发现:对Adapter的编写主要集中在几部分:

当然如果是非常简单的列表的话,其实Android原生的RecyclerView加上Adapter就已经比较便捷了,没有必要去做过度的封装了。

• Adapter中的ViewHolder模式 - 对于ListView来说,通过创建ViewHolder来提升性能并不是必须的。因为ListView并没有严格的ViewHolder设计模式。但是在使用RecyclerView的时候,Adapter必须实现至少一个ViewHolder,必须遵循ViewHolder设计模式。

  • 实现getView(int position, View convertView, ViewGroup parent)方法
  • 数据集合的增删修改,频繁手动调用 notifyDataSetChange()方法

项目GitHub地址: https://github.com/zhengcx/InstantRecyclerView

• 定制Item条目 - ListView只能实现垂直线性排列的列表视图,与之不同的是,RecyclerView可以通过设置RecyclerView.LayoutManager来定制不同风格的视图,比如水平滚动列表或者不规则的瀑布流列表。

而在getView()方法中,我们通常会做这么几件事:

   每一个对项目的重构或者重新封装都是出于对现状的不满,那么我们就从这个封装项目解决了哪些问题来展开这篇博文吧。

• Item动画 - 在ListView中没有提供任何方法或者接口,方便开发者实现Item的增删动画。相反地,可以通过设置RecyclerView的RecyclerView.ItemAnimator来为条目增加动画效果。

  • 设置布局文件
  • 数据与控件的绑定
  • 控件事件注册

1.解决重复的全局刷新

   需要注意一下你的项目里对列表的使用,特别是加载更多时是否都是重复的全局刷新,这对复杂列表的性能影响较大,你需要考虑每次刷新不去刷新那些不需要刷新的item,一个是对性能会有提高,另一个页面上用户的体验也会好很多,本项目提供了全局刷新和增量刷新的相关方法,保证加载更多或者操作单个item时只局部刷新。

• 设置数据源 - 在LisView中针对不同数据封装了各种类型的Adapter,比如用来处理数组的ArrayAdapter和用来展示Database结果的CursorAdapter。相反地,在RecyclerView中必须自定义实现RecyclerView.Adapter并为其提供数据集合。

转化成代码:

2.解决header/Footer的增删效率

   RecyclerView本身并没有提供像ListView那样便捷的添加header/footer的方法,所以需要我们自己去实现。

网上主要有两种:一种是采用wrap的方式使header、footer和普通item区别开,而另一种方式使把header、footer也当做是一种itemType来做。

   这里我们采用了第二种方式,提供了便捷添加header/footer的方法,当然把headerfooter当做一种itemType来看待,则当header/footer发生增删(特别是header)时,则会使列表发生全局的刷新,这里优化的点是对RecyclerView来说他的header永远只有一个,是一个ViewGroup,之后要添加或者删除一个或多个header,都只是往这个ViewGroup里增删View,将不会对整个列表产生刷新,提供性能和体验。

• 设置条目分割线 - 在ListView中可以通过设置Android:divider属性来为两个Item间设置分割线。如果想为RecyclerView添加此效果,则必须使用RecyclerView.ItemDecoration,这种实现方式不仅更灵活,而且样式也更加丰富。

 if (convertView == null) { convertView = View.inflate(context, getLayoutId; holder = new ViewHolder(convertView); convertView.setTag; } else { holder = convertView.getTag(); } bindItem(); //绑定数据 setEvent(); //绑定事件 return convertView;

3. 解决列表多itemType时代码不够清晰的问题

   当你的列表会存在多种复杂的itemType时,很容易时Adapter里的代码产生混乱,且不够清晰,很难拓展。我们封装的目的是:
1.让每种itemType的处理逻辑交给各自的itemDelegate去处理,实现不同itemType处理逻辑的解耦

2.让代码易于拓展,也就是说不管今后要再添加多少种itemType,都能做到非常清晰,非常便捷。

项目里通过DelegateScheduler来管理调度不同itemType的处理逻辑,使多itemType变得清晰易拓展。

• 设置点击事件 - 在ListView中存在AdapterView.OnItemClickListener接口,用来绑定条目的点击事件。但是,很遗憾的是在RecyclerView中,并没有提供这样的接口,不过,提供了另外一个接口RcyclerView.OnItemTouchListener,用来响应条目的触摸事件。

由于Adapter可多个itemType,因此封装的时候缤纷两路,RecyclerAdapter的封装也是如此。

4.解决状态View导致过度绘制的问题

   我们的列表通常都需要好几种显示加载状态的View,比如loadingView、加载失败View、加载数据为空View。如果你的做法是在布局文件里先写好这几种View然后通过设置是否可见来控制,显然这会引起布局嵌套过渡绘制的问题,当然你可以利用ViewStub来做一些优化,但是治标不治本,当这些状态View被inflate一次后,依然会存在这种问题。

   如果你把这些状态View也当做是一种itemType呢,让它与普通item一样参与回收,参与cache,是不是就可以解决这个问题,这是我目前看到想到的比较理想的方式,当然可能有更好的方式。

但是……,RecyclerView不像ListView那样拥有Header和Footer,因此开发中需要我们自己去实现Header和Foote,另外开发中小伙伴们经常使用的PullToRefresh库暂时又不支持RecyclerView。和身边的很多小伙们一样,我也陷入了困境,为了不拖累项目进度,我决定亲自解(shi)决(yong)难(kai)题(yuan),做一个伸手党。

Step1 封装XListAdapter,作为所有Adapter的基类,子类可实现getView()方法

XListAdapter中主要实现了数据集的增删修改常用操作事件绑定接口 等功能。

+ addData()+ setData()+ clearData+ addElement()+ removeElement()+ getColor()+ getDrawable()+ visible+ invisible()...

5.解决上拉加载更多问题

   显然如果你把上拉加载更多这个功能放在你的业务代码里去监听是不合适的,我们需要封装一下,让recyclerView自动就带有这个功能,直接使用就可以了。

   本项目给上拉加载更多提供了两种不同的监听方式,看个人喜好自己选择。
1.实时监听,也就是说只要用户滑动,那么就会实时监听判断要不要开始加载下一页数据,这一种的好处是让列表预加载更加实时,基本可以实时用户可以不断的下拉,使用户感知不到我们的加载过程。

2.另一种是只有当列表滚动状态发生改变时才会发起是否加载下一页数据的判断,这一种基本是用户从滑动到停止时才会发起下一页的加载。

当然两种方式提前多少个item发起预加载下一页都是可以由你自己来设置这个参数,目前默认是采用第二种方式,可以通过设置来使用第一种方式。

现在将我发现的GitHub上优秀的Header、Footer、上拉加载和下拉刷新解决方案汇总如下:

Step2 封装SimpleListAdapter,实现单viewType的需求

核心如下:

 @Override public View getView(int position, View convertView, ViewGroup parent) { H holder = null; T item = data.get; if (convertView == null) { convertView = View.inflate(context, getLayoutId; holder = newViewHolder(convertView); convertView.setTag; } else { holder =  convertView.getTag(); } convert(holder, item, position); return convertView; }

子类则摆脱了这段魔鬼一样的代码,只需要实现这三个方法:

protected abstract H newViewHolder(View convertView); //创建viewHolderprotected abstract int getLayoutId(); //设置布局资源idprotected abstract void convert(H holder, T item, int position); //数据绑定与事件绑定

6. 解决item的点击事件重复绑定的问题

   RecyclerView没有像ListView那样提供setOnItemCLickListener()方法来绑定item的点击事件,所以我们一般都会自己去设置这个item的点击事件,这样子很容易就把点击事件多次重复设置了。

   这里封装提供了setOnItemClickListener()方法,让你可以放心的设置item点击事件,并且在回调里提供该item所绑定的数据,以及item的position,该item的类型等重要信息,可以使你在多种itemType的列表里的点击事件里正确的做各种你想做的事情。

(一) SwipeToLoadLayout-推荐使用

Step3 事件绑定接口

为了方便事件的统一处理,我抽象了一个抽象类ListItemCallback

 public void onItemClick(int position, T model, int tag) {} //单击 public void onItemLongClick(int position, T model, int tag) {} //长按

参数:

  • position : 就是getView中的position,位置
  • model : 绑定的数据实体
  • tag : 事件标识,自己定义

a. 为什么定义的是抽象类,而不是接口?

因为接口中的方法需要全部实现,而抽象类可以选择性的override,显然,我们通常只需要重写onItemClick方法

b. 如何使用呢?

holder.itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick { if (getCallback() != null) { getCallback().onItemClick(position, item, TAG_VIEW); } } });

c. 为什么我不选择很常见的SparseArray那种封装的CommonAdapter

因为我不喜欢那种编码style,建议将Adapter单独类

RecyclerView的封装一般体现在:

  • 下拉刷新、上拉加载更多
  • header、footer
  • divider
  • ...

鉴于此,我之前搞了个ARecyclerView,主要有这些特性:

  • ARecyclerView继承自RecyclerView,它就是一个封装了常见功能的RecyclerView,而不是继承FrameLayout
  • ARecyclerView中实现了Header、Footer,header和Footer可以有多个
  • ARecyclerView的每一个header、footer的viewType是不同的,而大部分开源库的header、footer的viewtype是相同的,其直接后果是界面卡顿
  • ARecyclerView可以做出几乎任何的界面效果,可以取代ScrollView,你只需要使用header或者footer
  • ARecyclerView中实现了上拉加载更多,可以自定义加载更多的效果,只需要实现LoadMoreUIHandler接口即可
  • ARecyclerView并未实现下拉刷新功能,您可以选择SwipeRefreshLayout或者其他的下拉刷新viewGroup包裹,即你可以自由选择下拉刷新功能的实现。
  • 为了方便自定义使用,特别集成了XRecyclerContentLayout控件,你可以根据业务进行扩展,XRecyclerContentLayout只是一个示例,当然也可以满足绝大部分需求了

由于其实现相对复杂,推荐大家可以去看看源码,app mudule中是完整的实例

XDroid中,我新增了SimpleRecAdapter,应对单itemType的需求。具体思想和ListAdapter很相似

public abstract class SimpleRecAdapter<T, F extends RecyclerView.ViewHolder> extends RecyclerAdapter<T, F> { public SimpleRecAdapter(Context context) { super; } @Override public F onCreateViewHolder(ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext.inflate(getLayoutId(), parent, false); return newViewHolder; } public abstract F newViewHolder(View itemView); public abstract int getLayoutId();}

T 是item的实体类,F是ViewHolder的实体类

下一篇会谈谈ContentLayout的实现过程。

XDroid项目是我在两年的开发中积累的一个Android快速开发框架,目前包含UI层、缓存、图片加载、日志、路由、Api请求、事件订阅、工具类等。下一步会进行mvp、rx全家桶、retrofit、权限适配等工作。欢迎大家提出宝贵意见,指正不足。

最后附上链接:

对列表性能问题的建议

   其实对于一些复杂的列表,性能问题显得尤为重要,上面说了一个是尽量去做局部刷新而不是全量刷新,一个是尽量减少过度绘制。还有一个非常重要的是每个版本都要去关注你的bindViewHolder()里的逻辑是否有耗时严重的方法或操作,列表性能出现问题,很大概率就是你的bindViewHolder()中有叫耗时操作,排查也很好排查,通过SysTrace+TraceView可以很快找到耗时的方法和性能的瓶颈,然后做针对性的优化就可以了。

项目GitHub地址: https://github.com/zhengcx/InstantRecyclerView

最后,希望世界上的每一个列表都丝丝如滑~~~

GitHub地址:https://github.com/Aspsine/SwipeToLoadLayout

SwipeToLoadLayout支持YouTube、Google、京东等多家APP基于RecyclerView的上拉加载和下拉刷新样式,,好用的不要不要的。废话不多说,直接上图:

• ListView & GridView

美高梅棋牌官网 1

• RecyclerView(With all kinds of layoutManagers)

美高梅棋牌官网 2

• WebView & ScrollView & Other Views

美高梅棋牌官网 3

• Google SwipeRefreshLayout style

美高梅棋牌官网 4

• 京东style

美高梅棋牌官网 5

• Yalantis Phoenix 样式

美高梅棋牌官网 6

AndroidStudio配置方法

第一步:在你的build.gradle添加JitPack库在

repositories {

maven { url “https://jitpack.io” }

}

第二部:添加依赖库

dependencies {

compile ‘com.github.Aspsine:SwipeToLoadLayout:v1.0.2’

}

(二) UltimateRecyclerView-大名鼎鼎

GitHub地址:https://github.com/cymcsg/UltimateRecyclerView

UltimateRecyclerView是解决RecyclerView下拉刷新,加载更多,增加头部,显示或隐藏工具栏等许多问题的知名开源框架。

包含特性如下:

• Swipe to refresh(usingandroid.support.v4.widget.SwipeRefreshLayout)

• Many kinds of animations

• Swipe to dismiss

• Parallax or normal head view

• Drag and drop items

• Loading more when reach the last item(infinite scrolling)

• Custom views in loading more

• Showing or hiding toolbar and floating button when scrolling

• Scrollbars

• Colorful styles of swipe to refresh

• Sticky header like instagram

• Support different layout in adapter

• Loading adapter with animation

使用效果如下:

美高梅棋牌官网 7

美高梅棋牌官网 8

美高梅棋牌官网 9

美高梅棋牌官网 10

AndroidStudio配置方法

第一步:在你的build.gradle添加库

repositories {

jcenter()

maven { url"

}

美高梅棋牌官网 ,第二步:添加依赖库

dependencies{    compile'com.hkm.slidingmenulib:libmenu:0.4.9'}

第三步:布局文件中使用方法

< android:layout_width="fill_parent"

android:layout_height="fill_parent"

android:id="@+id/ultimate_recycler_view"/>

(三) IRecyclerView-效果最炫

GitHub地址:https://github.com/Aspsine/IRecyclerView

IRecyclerView支持RecyclerView下拉刷新,上拉加载,定制Header和Footer。

包含特性如下:

• pull-to-refresh

• pull-to-loadmore

• customize refresh header

• customize loadmore footer

• add multiple header view

• add multiple footer view

使用效果如下:

刷新效果

本文由美高梅游戏网站登录发布于美高梅棋牌游戏,转载请注明出处:同时通过封装来使复杂列表的性能得到一定的保

您可能还会对下面的文章感兴趣: