关于Paging + Room,RecyclerView刷新时的空指针异常

栏目: 数据库 · 发布时间: 6年前

内容简介:最近开了一个新项目,使用的是Google 2018 IO大会 推荐的新的app架构,如下:这里主要讲Paging + Room遇到的问题:基础的参考官方样例:

最近开了一个新项目,使用的是Google 2018 IO大会 推荐的新的app架构,如下:

关于Paging + Room,RecyclerView刷新时的空指针异常
官方地址

这里主要讲Paging + Room遇到的问题:

基础的参考官方样例: github.com/googlesampl…

PagedList的创建:

关于Paging + Room,RecyclerView刷新时的空指针异常

完全照搬官方的样例,传入自定义的BoundaryCallBack:

关于Paging + Room,RecyclerView刷新时的空指针异常

PagedList的DataSource.Factory:

关于Paging + Room,RecyclerView刷新时的空指针异常

实现交由子类:

关于Paging + Room,RecyclerView刷新时的空指针异常

Dao:

关于Paging + Room,RecyclerView刷新时的空指针异常

OK,到这里,基本上都是照搬的官方的样例了,接下来就看运行结果了:

关于Paging + Room,RecyclerView刷新时的空指针异常
数据能正确获取,并正确刷UI。但是,当数据超过30条(后面交代为什么是30)

时,具体效果如下:

关于Paging + Room,RecyclerView刷新时的空指针异常

PagedList的长度为50,但是只有30item是有数据的,其他都用null来占位了,

这会造成一个问题,当我需要删除一条数据时,删除后刷新UI,adapter的getItem()方法是会返回null,而我之所以用Paging + Room的形式,就是为了删除,因为PagedList不支持删除,233333。痛哭流涕啊。。。。。。。。

解题思路:

为什么PagedList里的其他数据是null,能不能把null去除

尝试一、发现PagedList的Config中有enablePlaceholders(支持占位)属性,默认为true,支持null,能不能改为false,这样PagedList中就不会有null

关于Paging + Room,RecyclerView刷新时的空指针异常
解决方案:
关于Paging + Room,RecyclerView刷新时的空指针异常

结果:

设置PagedList的配置enablePlaceholders为false后,PagedList的Observer接收到的数据并不完整,等于是PagedList将null数据过滤了。

只能往Room的源码挖了,为什么会返回null:

1、将Room与PagedList联系起来的是新建PagedList传入的Room产生的DataSource.Factory

关于Paging + Room,RecyclerView刷新时的空指针异常

2、寻找具体的DataSource

关于Paging + Room,RecyclerView刷新时的空指针异常

从FavorVideoDao的具体实现类中,可以看出,getAll()方法返回的是LimitOffsetDataSource,而其中只有恰巧只有一个返回集合为List< Object>的方法,参数为Cursor,所以应该能断定是从数据库中查出数据后处理返回给PagedList的方法。

3、Debug后发现,Cursor的长度与PagedList的Observer接收到的数据长度一致,所以由表入里,看看这个方法的上游是哪,为什么cursor中会有null的数据

关于Paging + Room,RecyclerView刷新时的空指针异常

LimitOffsetDataSource.loadRange()

关于Paging + Room,RecyclerView刷新时的空指针异常
从这个方法,我们能发现Cursor的由来,mDb.query(sqLiteQuery);

,Sqlite语句sqLiteQuery的由来就有意思了,

关于Paging + Room,RecyclerView刷新时的空指针异常

limit ? offset ? ,查询多少个,偏移多少(从第几个开始),到这里其实就有点眉目了

而这两个值其实来自与方法的参数:

关于Paging + Room,RecyclerView刷新时的空指针异常

4、查找limit和offset的由来 LimitOffsetDataSource.loadInitial():

关于Paging + Room,RecyclerView刷新时的空指针异常

PositionalDataSource.computeInitialLoadPosition(): offset:

public static int computeInitialLoadPosition(@NonNull LoadInitialParams params,
            int totalCount) {
        int position = params.requestedStartPosition;
        int initialLoadSize = params.requestedLoadSize;
        int pageSize = params.pageSize;

        int roundedPageStart = Math.round(position / pageSize) * pageSize;  // 这里肯定是大于0的

        // maximum start pos is that which will encompass end of list
        int maximumLoadPage = ((totalCount - initialLoadSize + pageSize - 1) / pageSize) * pageSize; // 所以必须保证maximumLoadPage小于等于0,所以必须保证 initialLoadSize必须足够大
        roundedPageStart = Math.min(maximumLoadPage, roundedPageStart);

        // minimum start position is 0
        roundedPageStart = Math.max(0, roundedPageStart);  // 所以,roundedPageStart必须小于等于0

        return roundedPageStart;
    }
复制代码

如果想要将所有数据都加载出来,offset必须的保证为0,具体看上面代码注释,所以关键在于params.requestedLoadSize

PositionalDataSource.computeInitialLoadSize(): limit:

public static int computeInitialLoadSize(@NonNull LoadInitialParams params,
            int initialLoadPosition, int totalCount) {
        return Math.min(totalCount - initialLoadPosition, params.requestedLoadSize); // 总的个数减去加载的起始位置  params.requestedLoadSize 两数去最小值,为加载的总个数
    }
复制代码

所以当params.requestedLoadSize足够大时,数据库中的所有数据都会被取出

Room加上limit逻辑,也是为了效率更高,但是因为有删除的业务需求,导致异常,所以还是每次全部都取出,RecyclerView刷新时,页只会刷新可见的Item,所以性能上还是OK的

5、查找params.requestedLoadSize的由来

PositionalDataSource.dispatchLoadInitial(),来源于该方法的参数,还是得往上寻找:

关于Paging + Room,RecyclerView刷新时的空指针异常

TiledPagedList的构造方法:

关于Paging + Room,RecyclerView刷新时的空指针异常
来源于Config的initialLoadSizeHint属性,所以最后回到了PagedList的Config的initialLoadSizeHint属性。此处正好回答前面为什么只保存30个数据了:
关于Paging + Room,RecyclerView刷新时的空指针异常

当未设置Config的initialLoadSizeHint属性时,默认为PageSize的3倍。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

网易一千零一夜

网易一千零一夜

网易杭研项目管理部 / 电子工业出版社 / 2016-9-1 / 46

本书是网易杭州研究院项目管理部多年来丰富的项目管理实践总结与干货分享。字字句句凝结了网易项目经理的甘与苦、汗与泪。 全书围绕项目管理体系,从敏捷实践、项目立项、需求管理、沟通管理,到计划进度管理、风险管理,真实反映了网易面向互联网产品项目管理实战经验与心路历程。 不论你是项目管理新手,还是资深项目经理,都可以从本书中获得启发与借鉴。一起来看看 《网易一千零一夜》 这本书的介绍吧!

随机密码生成器
随机密码生成器

多种字符组合密码

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器

html转js在线工具
html转js在线工具

html转js在线工具