本文介绍了RecyclerView适配器采用错误的值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个RecyclerView,它显示了两种View,一种代表用户发布,另一种代表事件发布.两者都有共同的元素,例如显示时间戳的TextView.因此,我创建了一个PublicationViewHolder,它将这个TextView时间戳记放入一个变量中并加载它.我的问题是,适配器最初会加载正确的值,但是当我向下滚动并再次向上滚动时,位置中的值会被另一个位置中的值更改.这是代码:

I have a RecyclerView which shows two kinds of Views one represents an User publication and another that represents an Event publication. Both have elements in common, for example a TextView that shows a time stamp. So I created a PublicationViewHolder that takes this TextView time stamp into a variable and load it. My issue is that the adapter, initially, load the right values, but when I scroll down, and scroll up again, the values in the positions are changed by values from another positions. Here is the code:

public class PublicationViewHolder extends RecyclerView.ViewHolder {

    private TextView vTimeStamp;

    public PublicationViewHolder(View itemView) {
        super(itemView);
        this.vTimeStamp = (TextView) itemView.findViewById(R.id.txt_view_publication_timestamp);
    }

    public void load(Publication publication, int i) {
        load(publication);
        try {
            if (Publication.TYPE_USER_PUBLICATION == publication.getType()) {
                load((UserPublication) publication);
            } else if (Publication.TYPE_EVENT_PUBLICATION == publication.getType()) {
                load((EventPublication) publication);
            }
        } catch (ClassCastException e) {
            throw new RuntimeException("Publication type cast fail. See PublicationViewHolder.");
        }
    }

    public void load(Publication publication) {
        vTimeStamp.setText(DateFormatter.getTimeAgo(publication.getTimeStamp()));
    }

    public void load( UserPublication publication) {
        //This method is override by UserPublicationViewHolder
    };

    public void load( EventPublication publication) {
        //This method is override by EventPublicationViewHolder
    };

}

现在,我将仅将UserPublicationViewHolder用于用户出版物.

Now I will make my UserPublicationViewHolder for users publications only.

public class UserPublicationViewHolder extends PublicationViewHolder {
    private  ImageView vImageView, vLikeButton, vDislikeButton, vFavButton, vEditPost, vDeletePost;
    private  TextView vText, vUsername, vLikeCount, vDislikeCount, vFavCount;
    private  PostImagesLayout vImagesContainer;
    private TagCloudLocationFriends tagsView;

    public UserPublicationViewHolder(View itemView) {
        super(itemView);
        vImageView = (ImageView) itemView.findViewById(R.id.img_view_publication_user);
        vText = (TextView) itemView.findViewById(R.id.txt_view_publication_text);

        vLikeCount = (TextView) itemView.findViewById(R.id.txt_view_like_count);
        vFavCount = (TextView) itemView.findViewById(R.id.txt_view_fav_count);
        vDislikeCount = (TextView) itemView.findViewById(R.id.txt_view_dislike_count);

        vUsername = (TextView) itemView.findViewById(R.id.txt_view_publication_user_name);
        vLikeButton = (ImageView) itemView.findViewById(R.id.img_view_like);
        vDislikeButton  = (ImageView) itemView.findViewById(R.id.img_view_dislike);
        vFavButton  = (ImageView) itemView.findViewById(R.id.img_view_fav);
        vImagesContainer = (PostImagesLayout) itemView.findViewById(R.id.container_post_images);

        tagsView = (TagCloudLocationFriends) itemView.findViewById(R.id.location_friends_tag);

        // edit - remove icons
        vDeletePost = (ImageView) itemView.findViewById(R.id.img_view_delete_post);
        vEditPost = (ImageView) itemView.findViewById(R.id.img_view_edit_post);
    }


    @Override
    public void load(UserPublication publication) {
        //Load the UserPublicationViewHolder specific views.
    }
}

现在,除了活动出版物,我将做同样的事情

Now I will do the same but for the Event publications

public class EventPublicationViewHolder extends PublicationViewHolder {

    private TextView vTextViewTitle;
    private TextView vTextViewText;

    public EventPublicationViewHolder(View itemView) {
        super(itemView);
        vTextViewTitle = (TextView) itemView.findViewById(R.id.txt_view_publication_event_title);
        vTextViewText = (TextView) itemView.findViewById(R.id.txt_view_publication_event_text);
    }

    @Override
    public void load(EventPublication publication) {
        //Load the EventPublicationViewHolder specifics views
    }
}

现在这是我的RecyclerView适配器:

Now here is my RecyclerView adapter:

public class PublicationAdapter extends RecyclerView.Adapter<PublicationViewHolder> {

    public static final int USER_PUBLICATION_TYPE = 1;
    public static final int EVENT_PUBLICATION_TYPE = 2;
    private List<Publication> publications = new ArrayList<Publication>();

    public List<Publication> getPublications() {
        return publications;
    }

    public void setPublications(List<Publication> publications) {
        this.publications = publications;
    }

    @Override
    public int getItemViewType(int position) {
        if (publications.get(position) instanceof UserPublication) {
            return USER_PUBLICATION_TYPE;
        }
        if (publications.get(position) instanceof EventPublication) {
            return EVENT_PUBLICATION_TYPE;
        }
        throw new RuntimeException("Unknown view type in PublicationAdapter");
    }

    @Override
    public PublicationViewHolder onCreateViewHolder(ViewGroup viewGroup, int type) {
        View v;
        switch (type) {
            case USER_PUBLICATION_TYPE:
                v = LayoutInflater.from(getActivity()).inflate(R.layout.view_holder_user_publication, viewGroup, false);
                return new UserPublicationViewHolder(v);
            case EVENT_PUBLICATION_TYPE:
                v = LayoutInflater.from(getActivity()).inflate(R.layout.view_holder_event_publication, viewGroup, false);
                return new EventPublicationViewHolder(v);
        }
        return null;
    }

    @Override
    public void onBindViewHolder(PublicationViewHolder aPublicationHolder, int i) {
        aPublicationHolder.load(publications.get(i), i);
    }

    @Override
    public long getItemId(int position) {
        //Here I tried returning only position or 0 without luck.
        //The id is unique BTW
        return publications.get(position).getId();
    }

    @Override
    public int getItemCount() {
        return publications.size();
    }

}

我不知道有什么问题,UserPublication和EventPublication都从Publication扩展而来.我没有做任何请求或重新加载适配器.我只加载一次适配器.

I don't know what can be wrong, UserPublication and EventPublication both extends from Publication. I'm not doing some request or reloading the adapter. I only load the adapter once.

更新:

顺便说一句,我在一个Fragment内使用此RecyclerView,该Fragment加载在PageAdapter中,而PageAdapter加载在Fragment内的ViewPager中,也许是这个问题吗?

BTW I'm using this RecyclerView inside a Fragment which is loaded in a PageAdapter which is loaded in a ViewPager that is inside a Fragment, maybe is this the issue?

更新:这是其他绑定代码.

Update:This is the other binding code.

这是UserPublicationViewHolder的加载方法.

    @Override
    public void load(UserPublication publication) {
        PicassoHelper.publicationUser(getActivity(), publication.getUser().getAvatarUrl(),
                vImageView);
        vText.setText(publication.getText());
        vUsername.setText(publication.getUser().getName());
        boolean hasLocation = false;
        if (publication.getImages().length > 0) {
            vImagesContainer.setImages(publication.getImages());
        } else {
            vImagesContainer.setVisibility(View.GONE);
        }
        tagsView.setTags(new ArrayList<MinikastTag>());
        tagsView.drawTags();

        if(publication.getLocation() != null || publication.getTaggedFriends().size() > 0){
            if(publication.getLocation() != null){
                hasLocation = true;
                tagsView.add(new MinikastTag(1,"Post from ",1));
                tagsView.add(new MinikastTag(2, publication.getLocation().getName(), 2));
            }
            if(publication.getTaggedFriends().size() > 0){
                if(hasLocation)
                    tagsView.add(new MinikastTag(3," with ",1));
                else
                    tagsView.add(new MinikastTag(3,"With ",1));

                int i = 0;
                for(User aUser: publication.getTaggedFriends()){
                    MinikastTag aTag;
                    if(i == publication.getTaggedFriends().size() - 1 ) {
                        aTag = new MinikastTag(4, aUser.getName(), 3);
                        aTag.setUserID(aUser.getId());
                        aTag.setUserName(aUser.getName());
                        tagsView.add(aTag);
                    } else {
                        aTag = new MinikastTag(4, aUser.getName() + ", ", 3);
                        aTag.setUserID(aUser.getId());
                        aTag.setUserName(aUser.getName());
                        tagsView.add(aTag);
                    }
                    i = i+1;
                }
            }
        }
        tagsView.drawTags();

        // likes, dislikes, favs
        if(publication.getLikesAmount() > 0)
            vLikeCount.setText(String.valueOf(publication.getLikesAmount()));

        if(publication.getDislikesAmount() > 0)
            vDislikeCount.setText(String.valueOf(publication.getDislikesAmount()));

        if(publication.getLovesAmount() > 0)
            vFavCount.setText(String.valueOf(publication.getLovesAmount()));

        // reset buttons
        vFavButton.setPressed(false);
        vDislikeButton.setPressed(false);
        vLikeButton.setPressed(false);

        if(publication.getRelationship().equals("LOVE"))
            vFavButton.setPressed(true);
        else if (publication.getRelationship().equals("LIKE"))
            vLikeButton.setPressed(true);
        else if (publication.getRelationship().equals("DISLIKE"))
            vDislikeButton.setPressed(true);

        // edit - remove icons

        if(String.valueOf(publication.getUser().getId()).equals(StartupSharedPreferences.getProfileId())){
            vEditPost.setVisibility(View.VISIBLE);
            vDeletePost.setVisibility(View.VISIBLE);
        }else{
            vEditPost.setVisibility(View.INVISIBLE);
            vDeletePost.setVisibility(View.INVISIBLE);
        }
    }
}

这是EventPublicationViewHolder的加载方法:

And this is the load method of the EventPublicationViewHolder:

@Override
public void load(EventPublication publication) {
    vTimeStamp.setVisibility(View.GONE);
    itemView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            //GoTo.eventDetail(getActivity(), publication);
        }
    });
    vTextViewTitle.setText(publication.getTitle());
    vTextViewText.setText(publication.getText());
}

我只是因为正在测试而评论了一些代码,但是如您所见,我只执行setTexts并添加一些图像.

I commented some code just because I was testing, but as you can see, I only do setTexts and assing some images.

这就是我设置适配器,LinearLayoutManager等的方法.在片段的onViewCreated方法中.

And this is how I set the adapter, LinearLayoutManager, etc. In the onViewCreated method of the fragment.

vRecyclerView = (FixedRecyclerView) view.findViewById(R.id.recycler_view_publications);
        vSwipeRefresh = (SwipeRefreshLayout) view.findViewById(R.id.swipe_container);
        mFeedCallback.onScrollReady(vRecyclerView);
        mLayoutManager = buildLayoutManager();
        vRecyclerView.setLayoutManager(mLayoutManager);
        vRecyclerView.addItemDecoration(new DividerItemDecoration(getActivity(), DividerItemDecoration.VERTICAL_LIST));
        mAdapter = new PublicationAdapter();
        vSwipeRefresh.setOnRefreshListener(this);
        vSwipeRefresh.setColorSchemeResources(R.color._SWIPER_COLOR_1, R.color._SWIPER_COLOR_2,
                R.color._SWIPER_COLOR_3, R.color._SWIPER_COLOR_4);
        vRecyclerView.setAdapter(mAdapter);

顺便说一句,适配器通过我拥有的自定义方法(称为onHttpClientReady)加载了数据集,但这似乎不是问题.

BTW The adapter is loaded with the dataset in a custom method that I have, called onHttpClientReady, but this doesn't seems to be the issue.

以下是一些屏幕截图:

当我第一次进入应用程序时,该列表的顶部:

Top of the list when I enter in the app for first time:

然后,当我回来时:

Then when I come back:

BTW的喜欢",不喜欢"和收藏夹"按钮,如果有人多次单击它们,将显示一个数字值,如果该值也不正确,则会放错位置.

BTW the like, dislike and favorite buttons, if someone did click them more than once, will display a numerical value, this values also are misplaced if they are.

更新:现在我知道那不是因为嵌套的片段.现在,我以如下方式更改了代码,即每个选项卡片段都位于Activity内ViewPager内的PageStateAdapter中.但是问题仍然存在.

UPDATE:Now I know that wasn't because the nested fragments. I changed my code in the way that, now, each tab fragment is in the PageStateAdapter that is inside the ViewPager that is inside an Activity. But the issue is still there.

更新:我发现getItemId方法从未执行过,IDK为什么仍未执行.

UPDATE:I found that the getItemId method is never being executed, IDK why yet.

推荐答案

我建议检查一下您的类层次结构和用法.通常,如果您在基类中执行type == type类操作,那么您将无法达到抽象和继承的目的.这样的事情将为您工作:

I'd suggest reviewing your class hierarchy and usage. In general, if you are doing a type == type kind of operation in a base class then you are defeating the purpose of the abstraction and inheritance. Something like this would work for you:

public abstract class PublicationViewHolder extends RecyclerView.ViewHolder {
    private TextView mTimeStamp;

    public PublicationViewHolder(View itemView) {
        mTimeStamp = (TextView)itemView.findViewById(R.id. txt_view_publication_timestamp);
    }

    public void bindViews(Publication publication) {
        mTimeStamp.setText(DateFormatter.getTimeAgo(publication.getTimeStamp()));
    }
}

现在,您的事件"或用户出版物"仅从此类派生并实现构造函数和bindViews()方法. 请务必在两种情况下都调用超类. 此外,请确保在版面中为特定出版物设置每个视图您的bindViews()方法.

Now your "event" or "user publications" simply derive from this class and implement the constructor and bindViews() method. Be sure to call through to the superclass in both cases. Also, be sure that you set every view in the layout for the specific publication in your bindViews() methods.

在适配器中,您只需要根据数据集中该位置上的发布类型创建正确的持有人即可:

In your adapter, you just need to create the correct holder based on the publication type at that position in your data set:

public class PublicationAdapter extends RecyclerView.Adapter {
    private ArrayList<Publication> mPubs;

    //  Your other code here, like
    //  swapPublications(), getItemCount(), etc.
    ...

    public int getItemViewType(int position) {
        return mPubs.get(position).getType();
    }

    public PublicationViewHolder createViewHolder(ViewGroup parent, int type) {
        PublicationViewHolder ret;
        View root;
        LayoutInflater inflater = LayoutInflater.from(parent.getContext());

        if (type == USER_PUBLICATION_TYPE) {
            root =
                inflater.inflate(R.layout.view_holder_user_publication,
                    parent,
                    false);

            ret = new UserPubHolder(root);
        } else {
            root =
                inflater.inflate(R.layout.view_holder_event_publication,
                    parent,
                    false);

            ret = new EventPubHolder(root);
        }

        return ret;
    }

    public bindViewHolder(PublicationViewHolder holder, int position) {
        holder.bindViews(mPubs.get(position));
    }
}

这篇关于RecyclerView适配器采用错误的值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-03 01:33