问题描述
我有一个 RecyclerView
,它显示了两种 View
,一种代表用户发布,另一种代表事件发布.两者都有共同的元素,例如显示时间戳的 TextView
.因此,我创建了一个 PublicationViewHolder
,它将这个 TextView
时间戳记放入一个变量中并加载它.我的问题是适配器最初加载了正确的值,但是当我向下滚动并再次向上滚动时,位置中的值会被其他位置的值更改.代码如下:
I have a RecyclerView
which shows two kinds of View
s 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?
更新:这是另一个绑定代码.
这是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 和 ass 一些图像.
I commented some code just because I was testing, but as you can see, I only do setTexts and assing some images.
这就是我在片段的 onViewCreated 方法中设置适配器、LinearLayoutManager 等的方式.
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:
然后当我回来时:
顺便说一句,喜欢,不喜欢和喜欢的按钮,如果有人多次点击它们,将显示一个数值,如果它们是,这个值也会放错位置.
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 适配器采用错误的值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!