本文介绍了RecyclerView onBindViewHolder只有调用时getItemViewType chagnes的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有muliple viewtypes一个viewholder。

I have a viewholder with muliple viewtypes.

在滚动 onBindViewHolder getItemViewType 的变化值只调用。这使我的列表项不正确更新。

When scrolling onBindViewHolder is only called when getItemViewType changes value. This causes my list items to not be updated properly.

这是一个错误?还是我做错了什么在这里。这似乎从新 recyclerView 类很奇怪的行为。

Is this a bug? Or I'm i doing something wrong here. This seems very strange behaviour from the new recyclerView class.

下面是我的适配器:

package se.davison.smartrecycleradapter;

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.util.SparseIntArray;
import android.view.LayoutInflater;
import android.view.ViewGroup;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;

/**
 * Created by richard on 10/11/14.
 */
public class SectionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {


    private static final String TAG = SectionAdapter.class.getSimpleName();
    private final LayoutInflater inflater;
    private final int sectionLayoutId;
    private SparseIntArray positionSection;
    private LinkedHashMap<AdapterItem, List<AdapterItem>> items = new LinkedHashMap<AdapterItem, List<AdapterItem>>();
    private List<Class<? extends AdapterItem>> itemTypes = new ArrayList<Class<? extends AdapterItem>>(20);

    public SectionAdapter(Context context, int sectionLayoutId, LinkedHashMap<AdapterItem, List<AdapterItem>> items) {
        this.inflater = LayoutInflater.from(context);
        this.sectionLayoutId = sectionLayoutId;
        this.items = items;
        initList(items);
    }

    public SectionAdapter(Context context, int sectionLayoutId) {
        this.inflater = LayoutInflater.from(context);
        this.sectionLayoutId = sectionLayoutId;
        this.items = new LinkedHashMap<AdapterItem, List<AdapterItem>>();
        initList(items);
    }


    @Override
    public int getItemViewType(int position) {
        AdapterItem item = getItem(position);
        Log.d(TAG, position + ": class " + item.getClass());
        return itemTypes.indexOf(item.getClass());
    }

    @Override
    public int getItemCount() {
        int count = 0;
        if (items == null) {
            return 0;
        }

        for (AdapterItem key : items.keySet()) {
            count++;
            List<AdapterItem> childItems = items.get(key);
            if (childItems != null) {
                count += childItems.size();
            }
        }
        return count;
    }

    private void initList(HashMap<AdapterItem, List<AdapterItem>> items) {
        positionSection = new SparseIntArray(items.size());
        int count = 0;
        int sectionIndex = -1;
        for (AdapterItem key : items.keySet()) {
            Class headerClass = key.getClass();
            if (!itemTypes.contains(headerClass)) {
                itemTypes.add(headerClass);
            }
            List<AdapterItem> childItems = items.get(key);
            sectionIndex = count;
            if (childItems != null) {
                for (AdapterItem item : childItems) {
                    Class clazz = item.getClass();
                    if (!itemTypes.contains(clazz)) {
                        itemTypes.add(clazz);
                    }
                    positionSection.put(count, sectionIndex);
                    count++;
                }

            }
            count++;
        }
        setHasStableIds(true);
    }

    private AdapterItem getItem(int position) {

        int totalChildCount = 0;
        int separatorCount = 0;
        for (AdapterItem key : items.keySet()) {
            if (position == 0 || position == totalChildCount + separatorCount) {
                return key;
            }
            separatorCount++;
            List<AdapterItem> list = items.get(key);
            int couldCount = countList(list);
            if (position < totalChildCount + separatorCount + couldCount) {
                return list.get(position - (totalChildCount + separatorCount));
            }

            totalChildCount += couldCount;
        }

        return null;
    }

    public void setItems(LinkedHashMap<AdapterItem, List<AdapterItem>> items) {
        this.items = items;
        notifyDataSetChanged();
    }

    public void setItemsAtHeader(int id, List<AdapterItem> items) {
        AdapterItem header = null;
        for (AdapterItem key : this.items.keySet()) {
            if (key.headerId() == id) {
                header = key;
                break;
            }
        }
        if (header == null) {
            throw new IllegalArgumentException(String.format("No header with id %s is found", id));
        }
        setItemsAtHeader(header, items);
    }

    private void setItemsAtHeader(AdapterItem header, List<AdapterItem> items) {
        this.items.put(header, items);
    }

    private int countList(List<?> list) {
        return list == null ? 0 : list.size();
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
        AdapterItem firstItem = getFirstItemWithClass(itemTypes.get(viewType));
        return firstItem.onCreateViewHolder(inflater, viewGroup);
    }

    private AdapterItem getFirstItemWithClass(Class<? extends AdapterItem> clazz) {

        for (AdapterItem key : items.keySet()) {
            if (key.getClass() == clazz) {
                return key;
            }
            List<AdapterItem> childItems = items.get(key);
            if (childItems != null) {
                for (AdapterItem item : childItems) {
                    if (item.getClass() == clazz) {
                        return item;
                    }
                }
            }
        }
        throw new IllegalStateException("Something is wrong, you dont have any items with that class in your list");
    }


    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
        AdapterItem item = getItem(position);
        Log.d(TAG, "ITEM = " + item.getClass().getSimpleName());
        Log.d(TAG, "POS = " + position);
        if (item instanceof OneLineAdapterItem) {
            Log.d(TAG, "TEXT = " + ((OneLineAdapterItem) item).getText());
        }

        item.onBindViewHolder(viewHolder, position);
    }
}

我还抽象出来的​​项目,像这样:

I've also abstracted out the items like so:

public abstract class AdapterItem<VH extends RecyclerView.ViewHolder> {


    public boolean isHeader(){
        return false;
    }

    public int headerId(){
        return -1;
    }

    public abstract VH onCreateViewHolder(LayoutInflater inflater, ViewGroup parent);

    public abstract void onBindViewHolder(VH viewHolder, int position);
}

而对于部分

public class SectionAdapterItem extends AdapterItem<SectionAdapterItem.ViewHolder> {

    private String text;
    private boolean dividerVisible = false;

    public static class ViewHolder extends RecyclerView.ViewHolder{

        TextView titel;
        ImageView divider;

        public ViewHolder(View itemView) {
            super(itemView);
            titel = (TextView) itemView.findViewById(android.R.id.title);
            divider = (ImageView) itemView.findViewById(android.R.id.icon);
        }
    }

    public void setDividerVisible(boolean dividerVisible) {
        this.dividerVisible = dividerVisible;
    }

    public boolean isDividerVisible() {
        return dividerVisible;
    }

    @Override
    public boolean isHeader() {
        return true;
    }

    @Override
    public int headerId() {
        return super.headerId();
    }

    public SectionAdapterItem(String text) {
        this.text = text;
    }

    @Override
    public ViewHolder onCreateViewHolder(LayoutInflater inflater, ViewGroup parent) {
        return new ViewHolder(inflater.inflate(R.layout.top_header, parent, false));
    }

    @Override
    public void onBindViewHolder(ViewHolder viewHolder, int position) {
        viewHolder.titel.setText(text);
        viewHolder.divider.setVisibility(dividerVisible?View.VISIBLE:View.GONE);
    }
}

它工作正常的弗里斯特可见行,但随后失败。

It works fine for the frist visible rows, but then it fails.

推荐答案

我忘了落实 getItemId 在使用 setHasStableIds(真正的);

实施解决了这个问题!

这篇关于RecyclerView onBindViewHolder只有调用时getItemViewType chagnes的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-22 11:49