RecyclerView滚动使findViewHolderForAdapterPosition返回null

时间:2017-04-11 04:06:13

标签: android nullpointerexception android-recyclerview android-adapter

我有RecyclerView横向LinerLayout。它显示从10到1的数字,用于评价某些内容。

当我选择10并滚动回1并选择1.我必须更新UI以删除10上的选择并更新1上的选择。但是,当我使用findViewHolderForAdapterPosition()删除10上的选择时给了我一个NullPointerException

我使用getAdapterPosition()在ViewHolder中获得该职位。

然后,我使用该位置通过调用我的Recycler视图对象上的findViewHolderForAdapterPosition()来获取ViewHolder,并更新UI以从10中删除选择。

vh = (RatingRecyclerAdapter.ViewHolder)
                mRecycler.findViewHolderForAdapterPosition(previousPosition);
vh.textRating.setBackgroundResource(R.drawable.rating_background_selected_orange);;

通过一些测试,我发现当我尝试做同样的事情而不滚动它工作正常。但是,只有当我滚动它时才会给我一个NullPointerException

我该如何解决这个问题?

这里要求的是Adapter类的一些重要代码。

@Override
public void onBindViewHolder(RatingRecyclerAdapter.ViewHolder holder, int position) {
        String itemText = itemList.get(position);
        holder.textRating.setText(itemText);
}

public class ViewHolder extends RecyclerView.ViewHolder {

        TextView textRating;

        public ViewHolder(View itemView) {
            super(itemView);
            textRating = (TextView) itemView.findViewById(R.id.text_rating);
            textRating.setOnClickListener(ratingClickListener);
        }

        private final View.OnClickListener ratingClickListener = new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                int position = getAdapterPosition();
                if (callback != null) {
                    callback.onClickRating(v, position);
                }
            }
        };
    }

活动类

@Override
public void onClickRating(View view, int position) {
        RatingRecyclerAdapter.ViewHolder vh;
        int color;

        int previousPosition = mAdapter.getSelectedPosition();  //Get previously clicked postion if any.
        if (previousPosition == Constants.NO_ITEM_SELECTED) {
            // An item was selected first time
            vh = (RatingRecyclerAdapter.ViewHolder)
                    mRecycler.findViewHolderForAdapterPosition(position);
            mAdapter.setSelectedPosition(position);  // Save new item selected position.
            color = Utility.getItemColor(mAdapter.getSelectedRating());
            mAdapter.setSelectedRatingResource(vh, color);
            return;
        }

        if (position == previousPosition) // Same item was selected
            return;

        vh = (RatingRecyclerAdapter.ViewHolder)
                mRecycler.findViewHolderForAdapterPosition(previousPosition);
        color = Utility.getItemColor(mAdapter.getSelectedRating());
        mAdapter.setUnselectedRatingResource(vh, color); // Remove the previous selected item drawables.

        vh = (RatingRecyclerAdapter.ViewHolder)
                mRecycler.findViewHolderForAdapterPosition(position);
        mAdapter.setSelectedPosition(position); // Save new item selected position.
        color = Utility.getItemColor(mAdapter.getSelectedRating());
        mAdapter.setSelectedRatingResource(vh, color); // Set the new selected item drawables. Setting some background to indicate selection.

    }

2 个答案:

答案 0 :(得分:2)

正如Sevastyan写在评论中的那样,RecyclerView会在项目离开屏幕后立即回收视图。因此,如果我们为屏幕外的视图调用findViewHolderForAdapterPosition(),则会得到null值。 (我不是在确认这是实际情况。但是,这就是我的看法。)

所以我创建了一个类,它存储了RecyclerView中项目的所有数据,并存储了该项中所有项目的颜色和值。当我们填充视图时,根据存储在该类中的数据设置所有颜色。

PS:我感谢Sevastyan没有直接给我答案。但是,只给我了解Exception的原因。

答案 1 :(得分:0)

如果您的视图不在屏幕上,则可以回收缓存

如果它被回收,您可以在 onViewRecycled() 方法中处理或在视图变为可见时在 onBind() 中再次设置视图(如果需要)。

如果它没有被回收(没有为那个位置调用 onViewRecycled 方法),它可能被缓存了。您可以将缓存大小设置为零以防止这种状态发生。

recycler.setItemViewCacheSize(0)