背景
项目的数据管理中心中通过表格的形式展示所有的数据项。
| 点名 | 创建时间 | 坐标 | 2d距离 | 3d距离 | ... |
|---|---|---|---|---|---|
| xx | xx | xx | xx | xx | ... |
数据通过sqlite数据库进行存储,涉及到多张表,进入数据中心页面后通过多表查询,拿到cursor对象,然后通过RecyclerView结合Adapter在bindViewHolder时直接通过cursor指针偏移的方法从cursor中读取数据。
现在有一个需求,对某列数据排序时,默认通过sql语句指定的排序效果不能满足需求,要能支持自定义排序规则。
思考
1.增加内存list
第一想到的肯定是改造数据读取的实现方式,从cursor中读取到内存list中,再将list数据拿去做展示,在展示数据前对list中的数据进行二次操作。
这种方式虽然可行,但是项目经过多年的开发迭代,这种改造影响面较大,adapter中读取数据的方式都要从cursor中读改为从list中读,数据读取后还涉及到一些计算逻辑,几百行代码都要被改动,风险不太可控,只能作为备选方案。
2.动态调整cursor顺序
既然改造实现方式的方法不是首选,那么就要考虑有没有其他方式,然后想到拿到cursor后能不能动态的通过cursor去调整数据的顺序呢,很快就被证实这一点是不可行的,因为cursor只提供了读的能力。
3.在增加内存list基础上,排序后构建新的cursor传入
继续深入思考,既然如此,我能不能拿到cursor后直接将数据全部读取到内存list中,进行排序后,再构建一个自定义cursor传进去?
这种方式在技术上可行,对现有代码的影响程度较小,只涉及新增逻辑,不涉及现有逻辑修改。但是有一些比较明显的缺点,首先,要将所有数据先读到内存中,必然会对内存造成压力;其次,数据中心中的数据项涉及到多张表,表格列数超过20列,有些数据还需要进行二次计算得到,并且该功能还在不断的迭代中,在中间插一层读取所有列的操作,后期的维护会相当困难,所以也只能先作为备选方案放着。
4.读取排序列获取新旧数据映射关系
所以想要找到一种既能最大化的降低影响范围,又能尽量保证运行效率的实现方案,似乎并不容易,不过我们很快想到了一个折中的方法:拿到cursor后,只从cursor中读取当前要排序的那一列,记录其在cursor中原始的position1,然后将数对其进行排序,再记录下每个数据排序后的position2,以position2为key,以position1为value构建一个映射关系,在adapter bind 数据的时候,通过这个map映射就可以通过排序后的position拿到数据在cursor中实际对应的位置,通过move cursor就可以实现数据的排序效果了,这样做的好处是,对项目代码结构几乎无影响,adapter中复杂的数据读取和计算逻辑不需要做调整,只需要增加一个 adapterPosition 的方法就可以了。
当然这种实现方式存在的风险在于,数据绑定改变了position,由原始的position1改变为实际读取的position2处的数据,数据展示上没有问题,那么其他通过position定位数据的逻辑是否会受到影响,需要进行排查验证。
总结
第4种是我们最终采纳的最终实现方案,基于项目整体的考虑,第一,对现有逻辑影响最小,风险可控;第二,对后期维护不会造成困难,几乎没有影响;第三,在现有逻辑下,效率也能满足需求。当然,这并不是最好的实现方式,数据中心的数据加载本身也存在一些效率上的问题,有待后续进一步优化。