Baserecyclerviewadapterhelper: 关于 ListAdapter 和 DiffUtil

Created on 26 Aug 2019  ·  10Comments  ·  Source: CymChad/BaseRecyclerViewAdapterHelper

@AllenCoder @limuyang2 看了下源码,这里是自己实现的?而 widget 包的 ListAdapter 用的是AsyncListDiffer,为什么没有直接用这个类呢?
如果是因为设计上的原因,需要自己重新写,那么想问下,为什么默认的方法:

DiffDemoCallback callback = new DiffDemoCallback(getNewList());
mAdapter.setNewDiffData(callback);

是同步的,而异步的需要写这么大段代码:

new Thread(new Runnable() {
    @Override
    public void run() {
        final List<DiffUtilDemoEntity> newData = getNewList();
        MyDiffCallback callback = new MyDiffCallback(newData, mAdapter.getData());
        final DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(callback, false);
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                mAdapter.setNewDiffData(diffResult, newData);
            }
        });
    }
}).start();

而 widget 的 AsyncListDiffer 的方法submitList就是异步计算的(假设 list 比较大,比方说1000个,计算就很耗时)。
这里能否把默认的 setNewDiffData 改为异步的,或者简化一下异步方法的 API 呢?

Most helpful comment

这么快吗,那可能我的担心多余了

dev中已经添加了一个简便方法,可拉取dev并参考其中的demo

All 10 comments

谢谢你提出的建议,之前确实是忽略了AsyncListDiffer。之后会补上。

不过通过查看源码,是使用的Handler实现的,其本质和demo中的用法是一样的。
关于你说的demo上给的示例是一大段代码,这个你仔细看看,仅仅是因为ThreadrunOnUiThread之间的切换。并且在项目中,并不会直接使用new Thread这种粗暴的写法,仅仅是作为使用示例。

AsyncListDiffer的源码中,是通过配置AsyncDifferConfig来从外部传入mMainThreadExecutor主线池、mBackgroundThreadExecutor多线程池,以达到外部对于多线程的控制。
根据我的感觉,其实本demo中的写法,对于线程的管理更加灵活,你只需要告诉adapter结果就行,至于Diff的计算过程,adapter并不关心。

不好意思,刚刚对AsyncListDiffer进行了尝试,发现AsyncListDiffer属于一个高度封装的类,其内部对list进行了自己的管理,无法对外响应。onBindViewHolder的方法需要大改动,只能从mDiffer.getCurrentList()中拿出数据,本库的mData就等于无用,但是setNewData()等等方法,都是依赖于我们自己管理的数据mData,这种大改动显然是不合理的。

AsyncListDiffer的意思是,所有设置数据的方法,只有submitList这一个内部方法,不论新增还是删除,然后其内部对list进行了自己的管理。

本库也有自己的mData管理list,并且有setNewData()addData()等等方法。此冲突无法解决。

并且AsyncListDiffer属于package android.support.v7.recyclerview.extensions;包下面的,并非属于基本api,而是属于一个扩展类。所以google的写法并无不问题,扩展类不是基础api,不需要考虑兼容问题。本库本质上也属于扩展库。扩展与扩展之间的冲突是正常的。

AsyncListDiffer的原理我上面也进行过解释,内部实现的很简单。现阶段可以自己实现异步,有更好的方式,例如:kotlin的协程。如果真的就想要google提供的简便方法,那请直接继承ListAdapter类。

后续我们会考虑加入简单的异步实现的,如需多线程管理,还是请按照demo中的示例,在外部进行线程管理,我们不想为了一个异步Diff,而在基类BaseQuickAdapter中封装一个线程池,过于繁重,因为不是每一个adapter都需要异步diff。

google的扩展ListAdapter类设计就是为了异步diff,所以内部封装线程池并无不妥。

不知我是否解释明白了

感谢详细的解释。那么没法实现一个比如 BaseQuickListAdapter 之类的吗

感谢详细的解释。那么没法实现一个比如 BaseQuickListAdapter 之类的吗

BaseQuickAdapter是所有类的父类,都是继承于此,只能在此基础上进行扩展

那么还是加入简单异步实现吧。同步方法感觉还是不要用为好

那么还是加入简单异步实现吧。同步方法感觉还是不要用为好

同步方法并没有太大性能问题,1w条数据以内,基本上都能在16ms内刷新

那么还是加入简单异步实现吧。同步方法感觉还是不要用为好

异步属于比较繁重的方法。异步和同步是互补的。不存在谁好谁坏。不同情况选择不同的方法而已

这么快吗,那可能我的担心多余了

这么快吗,那可能我的担心多余了

dev中已经添加了一个简便方法,可拉取dev并参考其中的demo

@limuyang2 单继承的话,那么 PagedListAdapter 打算怎么办呢?(Paging库)

Was this page helpful?
0 / 5 - 0 ratings