记一次反射解决XRecyclerView切换Adapter的小问题

最近在公司中做了个网盘的功能,里面涉及到很多知识点,也遇到了一些问题
其中有一个就是要切换xrecyclerview的适配器,不同种类的适配器
UI小姐姐给的图还是要做的,不然挨骂

日常给图


问题

本来是想不解决问题,解决提出问题的人,但是产品说这个必须要做,想了想,还是做吧
原始代码是这样的:

1
2
3
4
5
6
7
8
9
10
11
if (isLinear) {
rv.setLayoutManager(liLayoutManage);
rv.setItemAnimator(new SlideInUpAnimator());
rv.setAdapter(linearAdapter);
} else {
rv.setLayoutManager(grLayoutManage);
rv.setItemAnimator(new SlideInUpAnimator());
rv.setAdapter(gridAdapter);
gridAdapter.setOnLongClickListener(position ->
showSingleMorePopup(fileListBean.getData().getList().get(position)));
}

只留了核心的代码,但是这么写前两次点击是没有问题的,但是在第三次切换的时候就会出一个问题

经过一段时间的查询以及查看源码,大致明白了问题的原因
他这个是个观察者模式,xrecyclerview给每一个适配器都设置了个观察者,我猜应该是为了notifySetDateChange这个方法使用,因为这个是可以观测数据变化来改变布局的
但是每一次重新改变布局都要调用setAdapter,这个方法会默认给注册观察者,这就导致第二次切换适配器的时候报错
这也是xRecyclerView的一个bug,我对比了下recyclerview源码以及这个二次封装的xrecyclerview,发现了两个坑爹的点:

上图是xrecyclerview的源码,这里面是直接设置的DataObserver

而recyclerview中,人家第一步就是解除注册好不好!


解决办法

既然知道原因,就好办了
第一步就是帮助xrecyclerview解除切换前解除观察者的注册

1
2
3
if (linearAdapter.hasObservers()) {
linearAdapter.unregisterAdapterDataObserver(mDataObserver);
}

本来是想很简单就解决的,但是又来了个问题
这个mDataObserver我获取不到啊
我翻遍了xrecyclerview都没有找到这个东西在哪里获得
只好走点歪门邪道了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
 /**
* 解除观察adapter
*/
public void unRegisterObserver() {
Class clz = rv.getClass();
try {
Field oF = clz.getDeclaredField("mDataObserver");
oF.setAccessible(true);
RecyclerView.AdapterDataObserver mDataObserver = (RecyclerView.AdapterDataObserver) oF.get(rv);
if (isLinear) {
if (linearAdapter.hasObservers()) {
linearAdapter.unregisterAdapterDataObserver(mDataObserver);
}
} else {
if (gridAdapter.hasObservers()) {
gridAdapter.unregisterAdapterDataObserver(mDataObserver);
}
}
} catch (NoSuchFieldException | IllegalAccessException e) {
e.printStackTrace();
}
}

通过反射搞到他的私有变量,强行给他解绑观察者
使用就是在setAdapter之前提前调用这个方法就ok了


就这样啦,拜拜

请我喝杯咖啡吧~

支付宝
微信