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

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

Closed
@blesslp

Description

@blesslp

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

Activity

longerian

longerian commented on Aug 17, 2017

@longerian
Contributor

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

blesslp

blesslp commented on Aug 18, 2017

@blesslp
Author

嗯, 但是

当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

longerian commented on Aug 18, 2017

@longerian
Contributor

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

blesslp

blesslp commented on Aug 18, 2017

@blesslp
Author

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

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

longerian commented on Aug 19, 2017

@longerian
Contributor

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

wengqizun

wengqizun commented on Feb 27, 2018

@wengqizun

这个bug修复了吗?

longerian

longerian commented on Feb 27, 2018

@longerian
Contributor

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

yinyinnie

yinyinnie commented on Jun 12, 2019

@yinyinnie

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

yinyinnie

yinyinnie commented on Jun 12, 2019

@yinyinnie

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

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @longerian@yinyinnie@wengqizun@blesslp

        Issue actions

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