Android RecyclerView适配器使用错误的值
我有一个Android RecyclerView适配器使用错误的值,android,android-recyclerview,Android,Android Recyclerview,我有一个RecyclerView,它显示了两种视图,一种表示用户发布,另一种表示事件发布。两者都有共同的元素,例如显示时间戳的TextView。所以我创建了一个PublicationViewHolder,它将这个TextView时间戳放入一个变量并加载它。我的问题是适配器最初加载正确的值,但当我向下滚动并再次向上滚动时,位置中的值会被其他位置的值更改。代码如下: public class PublicationViewHolder extends RecyclerView.ViewHolder
RecyclerView
,它显示了两种视图,一种表示用户发布,另一种表示事件发布。两者都有共同的元素,例如显示时间戳的TextView
。所以我创建了一个PublicationViewHolder
,它将这个TextView
时间戳放入一个变量并加载它。我的问题是适配器最初加载正确的值,但当我向下滚动并再次向上滚动时,位置中的值会被其他位置的值更改。代码如下:
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
仅适用于用户出版物
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.
}
}
现在,除了活动出版物,我也将这样做
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适配器:
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();
}
}
这是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和assing一些图像
这就是我在片段的onViewCreated方法中设置适配器、LinearLayoutManager等的方法
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的自定义方法中,但这似乎不是问题所在
以下是一些屏幕截图:
当我第一次进入应用程序时,列表的顶部:
然后当我回来的时候:
顺便说一句,如果有人多次单击“喜欢”、“不喜欢”和“喜爱”按钮,则会显示一个数字值,如果这些值是错误的,则这些值也会被放错位置
更新:
现在我知道那不是因为嵌套的片段。我更改代码的方式是,现在,每个选项卡片段都位于活动中的ViewPager中的PageStateAdapter中。但问题仍然存在
更新:
我发现getItemId方法从未被执行,IDK为什么还没有执行。绑定代码中的一个大变量是日期格式:
DateFormatter.getTimeAgo(publication.getTimeStamp())
如果不直接查看该类,很难确定,但是看起来,如果时间戳是不可变的,但格式化程序基于当前时间,那么这将与视图恢复时文本的更改一致
我认为一个更大的问题是代码的可读性,这使得很难直观地发现问题。这里的继承模式和重载使得很难对代码进行推理,并决定采用哪条路径,以及它是否做了正确的事情。下面是一些napkin代码(尚未构建或运行),使用了更为组合的方法,这可能会使组织更清晰,更易于调试问题:
通用视图持有者代码的新助手类,替换了PublicationViewHolder
:
public class PublicationViewHolderHelper {
private final TextView vTimeStamp;
public PublicationViewHolder(View itemView) {
super(itemView);
this.vTimeStamp = (TextView) itemView.findViewById(R.id.txt_view_publication_timestamp);
}
/** Binds view data common to publication types. */
public void load(Publication publication) {
vTimeStamp.setText(DateFormatter.getTimeAgo(publication.getTimeStamp()));
}
}
public class EventPublicationViewHolder extends ViewHolder {
private final PublicationViewHolderHelper helper;
// View fields...
public EventPublicationViewHolder(View itemView) {
super(itemView);
helper = new PublicationViewHolderHelper(itemView);
// Populated view fields...
}
@Override
public void load(EventPublication publication) {
helper.load(publication);
//Load the EventPublicationViewHolder specifics views
}
}
public class PublicationAdapter extends RecyclerView.Adapter<ViewHolder> {
...
@Override
public void onBindViewHolder(ViewHolder viewHolder, int position) {
final Publication publication = publications.get(position);
final int viewType = getItemViewType(position);
switch (viewType) {
case USER_PUBLICATION_TYPE:
((UserPublicationViewHolder) viewHolder).load((UserPublication) publication);
break;
case EVENT_PUBLICATION_TYPE:
((EventPublicationViewHolder) viewHolder).load((EventPublication) publication);
break;
default:
// Blow up in whatever way you choose.
}
}
...
}
EventPublicationViewHolder
作为示例(对UserPublicationViewHolder
执行相同的操作):
请注意,现在适配器中没有基类,也不需要进行类型检查,因此代码要少得多
现在适配器保持不变,除了泛型类型和onBindViewHolder
:
public class PublicationViewHolderHelper {
private final TextView vTimeStamp;
public PublicationViewHolder(View itemView) {
super(itemView);
this.vTimeStamp = (TextView) itemView.findViewById(R.id.txt_view_publication_timestamp);
}
/** Binds view data common to publication types. */
public void load(Publication publication) {
vTimeStamp.setText(DateFormatter.getTimeAgo(publication.getTimeStamp()));
}
}
public class EventPublicationViewHolder extends ViewHolder {
private final PublicationViewHolderHelper helper;
// View fields...
public EventPublicationViewHolder(View itemView) {
super(itemView);
helper = new PublicationViewHolderHelper(itemView);
// Populated view fields...
}
@Override
public void load(EventPublication publication) {
helper.load(publication);
//Load the EventPublicationViewHolder specifics views
}
}
public class PublicationAdapter extends RecyclerView.Adapter<ViewHolder> {
...
@Override
public void onBindViewHolder(ViewHolder viewHolder, int position) {
final Publication publication = publications.get(position);
final int viewType = getItemViewType(position);
switch (viewType) {
case USER_PUBLICATION_TYPE:
((UserPublicationViewHolder) viewHolder).load((UserPublication) publication);
break;
case EVENT_PUBLICATION_TYPE:
((EventPublicationViewHolder) viewHolder).load((EventPublication) publication);
break;
default:
// Blow up in whatever way you choose.
}
}
...
}
公共类PublicationAdapter扩展了RecyclerView.Adapter{
...
@凌驾
公共无效onBindViewHolder(ViewHolder ViewHolder,int位置){
最终出版物=publications.get(位置);
最终int viewType=getItemViewType(位置);
开关(视图类型){
案例用户\出版物\类型:
((UserPublicationViewHolder)viewHolder)。加载((UserPublication)出版物);
打破
案例事件发布类型:
((EventPublicationViewHolder)viewHolder)。加载((EventPublication)出版物);
打破
违约:
//用你选择的任何方式爆炸。
}
}
...
}
请注意,它与您的
onCreateViewHolder
保持着非常相似的模式,因此不仅总体代码更少,而且内部一致性更高。这当然不是唯一的方法,只是基于您的特定用例的建议。我建议查看您的类层次结构和用法。一般来说,如果您在基类中执行type==type
类型的操作,那么您就违背了抽象和继承的目的。像这样的东西对你有用:
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()));
}
}
现在,您的“事件”或“用户发布”只是从这个类派生出来,并实现构造函数和bindwiews()
方法确保在这两种情况下都调用超类。另外,确保在bindViews()
方法中为特定出版物设置布局中的每个视图
在适配器中,您只需根据数据集中该位置的发布类型创建正确的保持架:
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));
}
}
公共类PublicationAdapter扩展了RecyclerView.Adapter{
私人ArrayList mPubs;
//你的另一个代码,比如
//swapppublications()、getItemCount()等。
...
public int getItemViewType(int位置){
返回mPubs.get(position.getType();
}
公共出版物ViewHolder createViewHolder(视图组父级,int类型){
出版物视图持有者ret;
视图根;
LayoutInflater充气器=LayoutInflater.from(parent.getContext());
if(type==用户\发布\类型){
根=
充气机。充气(右布局。视图\支架\用户\出版物,
父母亲
假);
ret=新用户pubholder(root);
}否则{
根=
充气机。充气(右布局。视图\支架\事件\出版物,
父母亲
假);
ret=新的EventPubHolder(根);
}
返回ret;
}
公众阅览员