Android中基于ListView的页面模块化

Android中基于ListView的页面模块化

  在很多App页面,我们经常需要去实现一个页面很长的页面,常常我们会选择ListView或者RecycleView去实现,因为这样的控件已经提供了view的缓存机制,可以帮助我们更好的去节省内存。但是如果我们实现的这个很长的页面业务模块很多,每个模块的业务都很复杂,每个模块自己的Item View的类型可能很多,同时不同的模块之间也有类似的View可以相互复用。这时候我们应该怎么去组织如此一个较为复杂的页面那。

  我们知道ListView获取每个Item的接口是其Adapter的GetView方法,对于上述的这种长页面,我们一种通常的做法就是将整个页面需要展示的各个模块的数据一起塞一个数据DataList中,然后在GetView方法中,根据这个DataList每个数据的数据类型去决定返回什么View和做什么样的业务逻辑。这样做当然可以实现这个页面,但是这样不是很好。因为

1)  模块化程度不高:不同的模块代码耦合比较重,无论是向DataList中塞数据或者Getview中返回Itemview,不同模块的业务代码都会交叉,会相互干扰。

2)  灵活性不高,调整不同模块之间的相对顺序不是很方便,特别是动态的去调整,比如刚进入页面的时候是ABC这种顺序,但是用户在做了某种操作后页面要变成CBA或者CDAB。做这样的变化时都不是方便,当然这跟1)中提到的模块化程度不高关系也很大。

 

  因此为了将页面各模块解耦,增加页面的灵活性,在页面的整体结构上将其模块化还是非常必要的。当然在采用ListView去实现整个页面时我们还需要处理一下ListView本身机制的几个问题,主要是View的复用机制上。

1)  viewType的count需要在ListView的setAdapter时就需要确定

2)  getViewType需要返回一个与ListView中的RecycleBin中的ViewCacheList的数组相对应的index值。

 

图1 总体结构图

图2 类图

 

本文介绍的方案主要结构图和类图如上所示,主要部分介绍如下:

1)  ModuleDataNode和ModuleDataGroupNode,整个页面模块结构的组成元素,整个页面的各个模块将以树形结构组织。叶子节点都是继承于ModuleDataNode这个类,Node节点只能代表一种ViewType类型,同时我们可以向Node中set数据,用起来类似一个adapter。ModuleDataGroupNode不会直接返回View,其作用主要用来组织和管理,他可以拥有ModuleDataNode类型的子节点,会根据当前ListView需要的index来计算出树中对应的Node叶子节点,从而返回相应的Item。同时在ModuleDataGroupNode这个层级虽然不返回ListView需要的展示的View,但是可以返回此Group的CoverView,所谓的CoverView就是当用户在滑动ListView的过程中,当某个Group的第一个item进入用户视野,其CoverView将覆盖在ListView上面,只是用户现在划入了此Group范围,当用户滑出此Group时,该CoverView将会消失。相信这个功能是一个很常见的功能,本方案中对其做了一些改进,主要是这个CoverView可以是多层的,也就是说可以在多个层次随意设置多个CoverView,页面会根据用户滑动的位置,遍历整个树结构,找出对应用户当前位置的所有的CoverView,并根据层级按由上至下的顺序做相应的展示。

2)  ViewCacheManagerBaseClass和BaseViewHolder。ViewCacheManagerBaseClass是页面中ItemView的一个创建工厂和管理器,BaseViewHolder是每种View的ViewHolder的父类。页面中所有Item的View都用这个ViewHolder封装,同时配置在ViewCacheManagerBaseClass中的ViewCacheTypeMap中,这样利用这个规则,整个页面的ViewType的Count就可以利用这个ViewCacheTypeMap的size确认。而不同ModuleDataNode将返回自己的ViewType String。在3)中介绍的ModuleDataAdapter中,会利用ViewCacheTypeMap和ViewType String将其转换成ListView的Recycle Bin锁需要的ViewTypeindex(int类型)。

3)  有了1)和2)所述的元素,我们就可以组成整个页面了。整个页面是ListViewWithCoveredView,它采用了组合模式wrap了一个ListView和CoverViewGroup,ListView就是整个整个页面的模块,而CoverViewGroup自然是展示每个Group的CoverView的。其中ListView对应所需的adapter是ModuleDataAdapter,它主要持有一个ModuleNode树的Root节点TopModuleDataNode,利用他返回不同index的View,ViewTypeCount,ViewType。从而整个页面即可以构造完成。

4)  在ModuleDataNode的数据改变或者ModuleDataGroupNode的子child改变时,我们都会立即同步通知到ModuleDataAdapter,这样保证了数据的一致性。

5)  特别提出的是,Moduel Node树所有操作需要在UI线程中操作,不能在子线程中做改变的操作,否则有可能数据会出错。

 

  这样整个的方案主要内容就介绍完了,总体思想就是将页面分成不同的Module从而解耦开来,所有的Module以树形的机构构造出整个页面的结构,后续的改变,比如增加模块,减少模块,改变模块展示的顺序,都是对这个Module树操作即开。让开发者只需要关心自己开发的模块,而不用管其它的模块。同时利用Listview这个大家很熟悉的控件展示,并提供了方便的复用策略。开发者只关注自己的Module后,可以在的Module中再去选择采用MVC、MVVM或者MVP等模式去构建自己Module内部的结构,因此整体页面还是可以很灵活的。

  当然,本文采取的是以ListView做为解决方案的基础,对于页面的View都是顺序的排列展示方式都可以搞定,如果是瀑布流的,确实会有瓶颈,此时采用RecycleView更为合适,但是本文的方案较为轻量,使用起来更为简单,对于很多场景还是非常适用的。

 

  本文代码的地址如下:https://github.com/heping851122/Module_ListView.git

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值