我有一个非常复杂的RecyclerView,由多个viewType组成。其中之一是ViewType.UNITS(我制作的代表每个viewType的枚举)。 UNITS具有需要显示的21个不同视图的数据。

当我向下滚动到recyclerView的底部时,一切都很好。当我向上滚动时,带有ViewType.UNITS的第一个视图(也许在整个position == 10中为recyclerView)被复制并显示在第三个ViewType.UNITS视图的位置。

所以这里向下滚动时是正确的:

UNIT1
UNIT2
UNIT3
UNIT4
UNIT5
...etc


但是当我向上滚动时,有时会看到以下内容:

UNIT1
UNIT2
UNIT1 //<-- problem here
UNIT4
UNIT5
...etc


viewHolder实例显示错误的数据。知道如何发生吗?

完整代码:

/**
 * An adapter for the recyclerView in the {@link HomeView}
 */
public class HomeRecyclerAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
    final String unitTitle;
    final Resources res;
    final SparseArray<ViewType> viewTypeCache;

    final SparseArray<MainArticleCategoryViewModel> mainArticleCategoryViewModelMap;

    public HomeRecyclerAdapter(Resources res) {
        this.res = res;
        unitTitle = res.getString(R.string.units_section_title);
        mainArticleCategoryViewModelMap = new SparseArray<>(GenericArticleCategory.MAIN.length);
        viewTypeCache = new SparseArray<>(getItemCount());
    }

    public static HomeRecyclerAdapter newInstance(Resources res) {
        return new HomeRecyclerAdapter(res);
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        final View v;
        switch (ViewType.getViewTypeFromInt(viewType)) {
            case PADDING_TOP:
                v = PADDING_TOP.inflateLayout(parent);
                return HeaderRecyclerViewHolder.newInstance(v);
            case HOME_BUCKET:
                v = HOME_BUCKET.inflateLayout(parent);
                return HomeBucketRecyclerViewHolder.newInstance(v);
            case UNITS_TITLE:
                v = UNITS_TITLE.inflateLayout(parent);
                return HomeTitleRecyclerViewHolder.newInstance(v);
            case UNITS:
                v = UNITS.inflateLayout(parent);
                return new HomeUnitsRecyclerViewHolder(v);
            case LINK_BUTTON:
                v = LINK_BUTTON.inflateLayout(parent);
                return HomeLinkRecyclerViewHolder.newInstance(v);

            default:
                throw new RuntimeException();
        }
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {

        switch (ViewType.getViewTypeFromInt(getItemViewType(position))) {
            case HOME_BUCKET:
                HomeBucketRecyclerViewHolder homeBucketRecyclerViewHolder = (HomeBucketRecyclerViewHolder) viewHolder;
                final GenericArticleCategory articleCategory = GenericArticleCategory.MAIN[position - HOME_BUCKET.getStart()];
                homeBucketRecyclerViewHolder.setArticleCategory(articleCategory);

                final MainArticleCategoryViewModel mainArticleCategoryViewModel = mainArticleCategoryViewModelMap.get(articleCategory.getId());
                if (mainArticleCategoryViewModel != null)
                    homeBucketRecyclerViewHolder.setImage(mainArticleCategoryViewModelMap.get(articleCategory.getId()).getFirstImageUrl());

                break;
            case UNITS_TITLE:
                ((HomeTitleRecyclerViewHolder) viewHolder).setText(unitTitle);
                break;
            case UNITS:
                final HomeUnitsRecyclerViewHolder homeUnitsRecyclerViewHolder = (HomeUnitsRecyclerViewHolder) viewHolder;
                homeUnitsRecyclerViewHolder.bind(GenericArticleCategory.UNITS[position - UNITS.getStart()]);
                break;
            case LINK_BUTTON:
                //all data needed for this is set via .xml, so no need to bind.
                break;
        }
    }

    @Override
    public int getItemViewType(int position) {
        ViewType viewType = viewTypeCache.get(position);
        if (viewType != null)
            return viewType.getItemViewType();


        if (isViewType(PADDING_TOP, position)) {
            viewType = PADDING_TOP;

        } else if (isViewType(HOME_BUCKET, position)) {
            viewType = HOME_BUCKET;

        } else if (isViewType(UNITS_TITLE, position)) {
            viewType = UNITS_TITLE;

        } else if (isViewType(UNITS, position)) {
            viewType = UNITS;

        } else if (isViewType(LINK_BUTTON, position)) {
            viewType = LINK_BUTTON;
        }

        if (viewType != null) {
            viewTypeCache.put(position, viewType);
            return viewType.getItemViewType();
        }

        throw new RuntimeException("There is no position that matches the position " + position);
    }

    @Override
    public int getItemCount() {
        int sum = 0;
        for (ViewType viewType : ViewType.values()) {
            sum += viewType.getItemCount();
        }
        return sum;
    }

    public boolean isViewType(ViewType viewType, int position) {
        if (viewType.getStart() <= position && position <= viewType.getEnd())
            return true;
        else
            return false;
    }

    public void addImage(MainArticleCategoryViewModel viewModel) {
        final int id = viewModel.getId();
        mainArticleCategoryViewModelMap.put(id, viewModel);
        notifyItemChanged(id);
    }

    public enum ViewType implements ViewTypeItem {
        HOME_BUCKET(0, R.layout.home_recycler_item_category) {
            @Override
            public int getStart() {
                return PADDING_TOP.getStart() + 1;
            }

            @Override
            public int getItemCount() {
                return GenericArticleCategory.MAIN.length;
            }
        },
        UNITS_TITLE(1, R.layout.home_recycler_item_title) {
            @Override
            public int getStart() {
                return HOME_BUCKET.getEnd() + 1;
            }

            @Override
            public int getItemCount() {
                return 1;
            }
        },
        UNITS(2, R.layout.home_recycler_item_units) {
            @Override
            public int getStart() {
                return UNITS_TITLE.getEnd() + 1;
            }

            @Override
            public int getItemCount() {
                return GenericArticleCategory.UNITS.length;
            }
        },
        LINK_BUTTON(4, R.layout.home_recycler_item_external_link_group) {
            @Override
            public int getStart() {
                return UNITS.getEnd() + 1;
            }

            @Override
            public int getItemCount() {
                return 1;
            }

        },
        PADDING_TOP(10, R.layout.seabee_resources_recycler_item_padding_top) {
            @Override
            public int getStart() {
                return 0;
            }

            @Override
            public int getItemCount() {
                return 1;
            }
        };

        private final int itemViewType;
        @LayoutRes
        private final int layoutResId;

        ViewType(int itemViewType, @LayoutRes int layoutResId) {
            this.itemViewType = itemViewType;
            this.layoutResId = layoutResId;
        }

        public static ViewType getViewTypeFromInt(int itemViewType) {
            for (ViewType viewType : ViewType.values()) {
                if (viewType.getItemViewType() == itemViewType)
                    return viewType;
            }
            throw new RuntimeException("There is no type that matches the itemViewType " + itemViewType + " + make sure your using types correctly");
        }

        public int getItemViewType() {
            return itemViewType;
        }

        @Override
        public int getEnd() {
            return getStart() + getItemCount() - 1;
        }

        private View inflateLayout(ViewGroup parent) {
            return LayoutInflater.from(parent.getContext()).inflate(layoutResId, parent, false);
        }

        public int getSpanSize(int homeGridTotalSpan, Resources res) {

            switch (this) {
                case PADDING_TOP:
                    return homeGridTotalSpan;
                case HOME_BUCKET:
                    return homeGridTotalSpan / res.getInteger(R.integer.home_bucket_span);
                case UNITS_TITLE:
                    return homeGridTotalSpan / res.getInteger(R.integer.home_title_span);
                case UNITS:
                    return homeGridTotalSpan / res.getInteger(R.integer.home_units_span);
                case LINK_BUTTON:
                    return homeGridTotalSpan / res.getInteger(R.integer.home_link_span);
                default:
                    throw new RuntimeException("Missing an enum in this switch statement");
            }
        }
    }

    interface ViewTypeItem {

        int getStart();

        int getEnd();

        int getItemCount();

    }


}

最佳答案

onCreateViewHolder()中,您不应再调用getViewTypeFromIntonCreateViewHolder()的第二个参数,即int itemViewType应该已经使用。

因此,只需更新您的onCreateViewHolder

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        final View v;
        switch (viewType) {
            case PADDING_TOP:
                v = PADDING_TOP.inflateLayout(parent);
                return HeaderRecyclerViewHolder.newInstance(v);
            case HOME_BUCKET:
                v = HOME_BUCKET.inflateLayout(parent);
                return HomeBucketRecyclerViewHolder.newInstance(v);
            case UNITS_TITLE:
                v = UNITS_TITLE.inflateLayout(parent);
                return HomeTitleRecyclerViewHolder.newInstance(v);
            case UNITS:
                v = UNITS.inflateLayout(parent);
                return new HomeUnitsRecyclerViewHolder(v);
            case LINK_BUTTON:
                v = LINK_BUTTON.inflateLayout(parent);
                return HomeLinkRecyclerViewHolder.newInstance(v);

            default:
                throw new RuntimeException();
        }
    }

08-18 18:57