天天看点

weex高性能list解析List示例list和UITableView的对比原理实现总结

而listview在移动端界面的开发中是非常重要的组件,无论是h5还是react-native都因为listview的低性能而饱受非议。那么到底是什么样的实现让weex能拥有与众不同的listview性能呢?

首先,让我们一起来看看weex下如何使用list。

cell:决定list中每个cell的样子

header:当list滑到顶部的时候,会吸在顶部

refresh:下拉刷新

loading:上拉加载更多

提供的功能虽然没有uitableview强大,但都是实际使用最需要的功能。上面list的demo使用到了<code>refresh</code>,<code>cell</code>以及<code>loading</code>子组件。

list的样式并不在本文的分析范畴,所以这里就pass了。

js部分定义了相关的回调,其中需要特别关注下的是<code>repeat="{{rows}}"</code>,其根据rows提供的数据重复创建多个cell。

先来看下在ios中我们是如何使用uitableview的:

继承<code>uitableviewcell</code>,实现自定义的cell样式。

初始化<code>uitableview</code>,设置<code>datasource</code>和<code>delegate</code>。

实现<code>datasource</code>,主要是设置<code>uitableview</code>的<code>section</code>数目,每个<code>section</code>的<code>cell</code>数目,以及每个cell的样式。

实现<code>delegate</code>,主要是实现在操作uitableview时候的一些委托,比如<code>tableview:didselectrowatindexpath:</code>等。

相比之下,weex的就简单多了:

实现cell样式。(对应于ios自定义cell的实现)

按需实现refresh或者loading或者其他。(uitableview默认没有下拉刷新和加载更多,一般通过<code>uiscrollview+svpulltorefresh</code>的扩展来实现)

设置数据,实现回调。(对应于ios实现datasource和实现delegate,不过显然功能弱一些)

其实从这里我们应该能够推断出一点什么了。没错,

weex的高性能list和其他框架不一样的地方就在于cell的重用,也就是充分利用了uitableview或者recycleview的重用机制实现了性能的优化。

以上结论还只是猜测(虽然我们都知道这是必由之路),那我们就继续扒扒代码看个清楚。

其实一点都不复杂,就是jscore或者v8做了一个桥,让native能和js共享一个context而已。

weex高性能list解析List示例list和UITableView的对比原理实现总结

js通过桥告诉了native现在有list组件,子组件有cell、refresh和loading。下面就直接扒native的代码看。

weex中用两个概念,一个是模块(module),一个是组件(component),前者主要是功能的,例如存储,而后者主要是视图,比如div这样的。很显然list、cell等都是组件类别的。

在wxsdkengine的源码中,可以知道<code>list</code>其实对应的是<code>wxlistcomponent</code>,<code>cell</code>对应的是<code>wxcellcomponent</code>,<code>header</code>对应的是<code>wxheadercomponent</code>等等。

因为即将讨论的都是组件,那就必须要先了解下weex的组件系统。

那当我们在说组件系统的时候,我们到底在说什么呢?在weex中其实就是weex的组件基类 —— <code>wxcomponent</code>。下面挑重点看看weex的组件系统都有哪些功能。

下面的这个代码比较能说明问题,uiview和calayer都是和wxcomponent一一对应的。这就是weex的组件系统和ios的组件系统建立联系的地方。

之上说的只是weex组件系统的一部分,组件系统还有一个非常重要个功能是布局。

在weex中,这一部分的功能是通过<code>wxcomponent+layout</code>来实现的,布局系统使用的是flexbox。列举几个主要是函数。

下面我们来看看cell组件的实现。

仔细查看wxcellcomponent的实现可以发现,其是没有什么特别特殊的地方,其与其他组件最大的不同就是对应有list组件,其所有的回调都会相应的调用list的方法,更新list中对自己的状态。比如:

refresh、loading以及header等都是类似的组件,这里就不详述了,有兴趣的同学可以查看源码阅读。

<code>wxlistcomponent</code>是本文的主角,放在最后出场也算是压轴了,首先来看一下头文件。非常简单,类似所有的<code>listview</code>,都是继承自<code>scrollview</code>,其还包括了一些针对cell操作的api,上面源码中的<code>celldidlayout</code>就是在这里定义的。

其实到这里我们已经知道cell、header、refresh、loading等都是如何根据js代码生成native组件的,现在,我们还不知道的是,list是怎么把他们拼在一起的。

下面的代码就能说明这一切。

从这里我们可以看到,listcomponent是依赖了tableview的。

从这里我们可以看到,list、cell、header、loading以及fixed-component是如何通过组件系统联系起来的。

再举另外一个例子。

再来看一下tableview的datasource,

weexsdk关于list的细节还非常多,但通过上面的分析,我们已经大致清楚了weex是如何利用uitableview来实现重用cell,提升性能的,稍微总结一下。

规定语法,list组件的子组件只能是cell、header、refresh、loading已经fixed-component

当指定cell、header、refresh、loading和fixed-component的时候,组件系统都会根据css计算出这些子组件的布局。

cell和header是比较特殊的组件,他们持有list的引用,会在自身发生变化的时候调用list组件方法更新list状态,而且他们出现的顺序会决定最终tableview的section数目和每个section的row的数目。

其实这里比较不一样的是weex会频繁的更新tableview,用到了很多<code>reloadrowsatindexpaths</code>、<code>insertrowsatindexpaths</code>、<code>deleterowsatindexpaths</code>等类似的方法,每个cell、header等的出现会让tableview发生变化。

再来看一下正常情况下我们使用uitableview。

准备数据

reload table

对table的改变次数远远少于weex的方案,因此weex应该还有是不少改进的地方。

在我的理解,tableview重用最核心的就是cell模板的复用,是不是可以想办法让js能定义cell模板,然后native就根据数据给的id来使用相应的模板来渲染list,从而避免了需要先渲染cell然后再来决定list的显示,期待weex牛逼的工程师们再给我们带来惊喜。

继续阅读