Skip to content
This repository has been archived by the owner on Jul 14, 2021. It is now read-only.

动态替换adapter的时候,导致adapter复用错误,强转异常 #182

Closed
blesslp opened this issue Aug 17, 2017 · 9 comments
Closed

动态替换adapter的时候,导致adapter复用错误,强转异常 #182

blesslp opened this issue Aug 17, 2017 · 9 comments

Comments

@blesslp
Copy link

blesslp commented Aug 17, 2017

事情是这样, 购物app的首页, 用到了多种多样的布局,其中有一些会根据服务器端给的模版来变化
这样,
因为数据的变化可能会导致我这边的adapter变化,所以我维护了一系列的List来保存一些模板Adapter
每次刷新界面,我就写了
delegateAdapter.removeAdapters(xx)
delegateAdapter.addAdapters(xx),
这样,首次进页面,没问题, 但是在有数据的前提下, 再次刷新后,就会报Adapter强转异常,这个强转是我写了ViewHolder导致的, 但是AAdapter里面传入了BAdapter的ViewHolder.
后来我寻思着,可能是复用出了问题, 然后我给每个Adapter都加了getItemType返回一个递增且唯一的int,就好了.
我是好奇这是我用法的问题,还是VLayout的复用逻辑有一些瑕疵?

@longerian
Copy link
Contributor

应该是复用相关的问题,参考FAQ:https://github.com/alibaba/vlayout/blob/master/docs/VLayoutFAQ.md 先检查一下代码

@blesslp
Copy link
Author

blesslp commented Aug 18, 2017

嗯, 但是

当hasConsistItemType=false的时候,即使不同DelegateAdapter.Adapter里返回的相同的itemType,对于DelegateAdapter也会将它转换成不同的值,对于RecyclerView来说它们是不同的类型。

这里我的hasConsistItemtype=false了,感觉Adapter的itemType返回了相同类型了,DelegateAdapter转换后的itemType还是同一个 , 我发现是这样的,就是Aadapter在位置3,返回type为0,后来数据变了,3这个位置变成BAdapter了,然后给BAdapter里面的ViewHolder被强转成Aadapter里面的ViewHolder导致了报错, 我把没个Adapter的itemType都写成不一样的, 这个问题就不存在了.

@longerian
Copy link
Contributor

恩,你加日志或者 debug,把 getItemViewType(int position) 方法的结果捞一把,确认一下在 Adapter 的 itemType 一样的情况下,最终的类型是否一样,应该是要不一样。

@blesslp
Copy link
Author

blesslp commented Aug 18, 2017

感谢您百忙中抽空解答 : )

Pair<AdapterDataObserver, Adapter> p = findAdapterByPosition(position);
        if (p == null) {
            return RecyclerView.INVALID_TYPE;
        }
        int subItemType = p.second.getItemViewType(position - p.first.mStartPosition);

        if (subItemType < 0) {
            // negative integer, invalid, just return
            return subItemType;
        }
        if (mHasConsistItemType) {
            mItemTypeAry.put(subItemType, p.second);
            return subItemType;
        }
        int index = p.first.mIndex;
        return (int) getCantor(subItemType, index);
  int index = p.first.mIndex;
  return (int) getCantor(subItemType, index);

我觉得这里好像是中了我说的情况了, 在同一个位置,由于数据的变动导致这里由Aadapter变成了BAdapter,但是如果我在adapter里面没有覆盖getItemType,默认返回0的话,

//例如:
index = 3;
subItemType=0;
//这样getCantor算出来的值是一样的,

所以这种情况会导致表层Adapter变了,而RecyclerView误认为是同一个,所以把之前的AAdapter的ViewHolder给了BAdapter,导致强转异常吧,
这种情况需要我们手动给A,B,C,Adapter指定不一样的itemType来保证在同一位置算出的Cantor唯一.
大神您看我说的对吗?

@longerian
Copy link
Contributor

longerian commented Aug 19, 2017

嗯,是的,这里有个瑕疵,没有考虑到替换adapter的情况,所以getCantor(subItemType, index)算出来恰好是一样的,导致复用成一个了。在没有想出好的解决办法之前,先通过指定不一样的itemType来保证吧。

@wengqizun
Copy link

这个bug修复了吗?

@longerian
Copy link
Contributor

建议使用 tangram 来使用vlayout,直接使用vlayout成本略高。 @wengqizun

@yinyinnie
Copy link

因为这个问题的存在的,所以在同一个列表中使用多个DelegateAdapter.simpleAdapter时,也存在复用的问题。

@yinyinnie
Copy link

建议使用 tangram 来使用vlayout,直接使用vlayout成本略高。 @wengqizun

如果vlayout存在这个问题,使用Tangram能规避这个问题吗?难道说Tangram内部做了处理?

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants