在嵌套 RecyclerView 中滚动时丢失数据
Losing data while scrolling in Nested RecyclerView
我正在开发一个聊天机器人,其中父适配器中有两种视图类型,其中 ReceivedMessageViewHolder 具有嵌套的回收器视图,我目前正在通过单击嵌套的回收器视图,但它似乎工作正常。但是当我从底部到底部滚动时,我最终丢失了嵌套回收器视图的最后一项的数据,父项仍在显示但子适配器在滚动时消失了。
我正在为 ParentAdapter、ChildAdapter 和 ItemClick Listener 添加我的代码。请看看并帮助我找出我正在做的错误或如何遇到问题。
ParentAdapter 代码:
public class MessageListAdapter extends RecyclerView.Adapter {
private Context mContext;
private static final int VIEW_TYPE_MESSAGE_SENT = 1;
private static final int VIEW_TYPE_MESSAGE_RECEIVED = 2;
private List<Payload> chatMessageList;
private OnItemClickListener onItemClickListener;
MessageListAdapter(Context context, List<Payload> chatMessageList, OnItemClickListener onItemClickListener) {
this.mContext = context;
this.chatMessageList = chatMessageList;
this.onItemClickListener = onItemClickListener;
}
@Override
public int getItemCount() {
return chatMessageList.size();
}
// Determines the appropriate ViewType according to the sender of the message.
@Override
public int getItemViewType(int position) {
Payload message = chatMessageList.get(position);
if (TextUtils.equals(message.getUserType(), "USER")) {
// If the current user is the sender of the message
return VIEW_TYPE_MESSAGE_SENT;
} else {
// If some other user sent the message
return VIEW_TYPE_MESSAGE_RECEIVED;
}
}
// Inflates the appropriate layout according to the ViewType.
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view;
if (viewType == VIEW_TYPE_MESSAGE_SENT) {
view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_user_msg, parent, false);
return new SentMessageHolder(view);
} else {
view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_bot_msg, parent, false);
return new ReceivedMessageHolder(view);
}
}
// Passes the message object to a ViewHolder so that the contents can be bound to UI.
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
Payload chatMessage = chatMessageList.get(position);
switch (holder.getItemViewType()) {
case VIEW_TYPE_MESSAGE_SENT:
((SentMessageHolder) holder).bind(chatMessage.getMessage(), getFormattedTime());
break;
case VIEW_TYPE_MESSAGE_RECEIVED:
((ReceivedMessageHolder) holder).bind(chatMessage.getMessage(), getFormattedTime());
((ReceivedMessageHolder) holder).bindRv(chatMessage, mContext);
break;
}
}
private static class SentMessageHolder extends RecyclerView.ViewHolder {
TextView txtViewChatMsgUser;
TextView txtViewDateTimeUser;
SentMessageHolder(View itemView) {
super(itemView);
txtViewChatMsgUser = itemView.findViewById(R.id.txtViewChatMsgUser);
txtViewDateTimeUser = itemView.findViewById(R.id.txtViewDateTimeUser);
}
void bind(String message, String time) {
txtViewChatMsgUser.setText(message);
txtViewDateTimeUser.setText(time);
}
}
private class ReceivedMessageHolder extends RecyclerView.ViewHolder {
TextView txtViewChatMsgBot;
RecyclerView rvDeepLink;
TextView txtViewDateTimeBot;
ReceivedMessageHolder(View itemView) {
super(itemView);
txtViewChatMsgBot = itemView.findViewById(R.id.txtViewChatMsgBot);
rvDeepLink = itemView.findViewById(R.id.itemRvDeepLink);
txtViewDateTimeBot = itemView.findViewById(R.id.txtViewDateTimeBot);
}
void bind(String message, String time) {
txtViewChatMsgBot.setText(message);
txtViewDateTimeBot.setText(time);
}
void bindRv(Payload chatMessage, Context context) {
if (chatMessage.getData() != null && !chatMessage.isOptionSelected()) {
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(context);
linearLayoutManager.setOrientation(RecyclerView.VERTICAL);
rvDeepLink.setLayoutManager(linearLayoutManager);
rvDeepLink.setHasFixedSize(true);
DeepLinkAdapter deepLinkAdapter = new DeepLinkAdapter(context, chatMessage.getData(), onItemClickListener, getAdapterPosition());
rvDeepLink.setAdapter(deepLinkAdapter);
} else {
rvDeepLink.setVisibility(View.GONE);
}
}
}
private String getFormattedTime() {
SimpleDateFormat dateFormat = new SimpleDateFormat("hh.mm aa", Locale.ENGLISH);
return dateFormat.format(new Date());
}
void onSelected(int position) {
chatMessageList.get(position).setOptionSelected(true);
notifyItemChanged(position);
}
}
子适配器代码:
public class DeepLinkAdapter extends RecyclerView.Adapter<DeepLinkAdapter.DeepLinkViewHolder> {
private List<DataItem> dataItemList;
private Context context;
private OnItemClickListener onItemClickListener;
private int parentPos;
DeepLinkAdapter(Context context, List<DataItem> dataItemList, OnItemClickListener onItemClickListener, int parentPos) {
this.context = context;
this.dataItemList = dataItemList;
this.onItemClickListener = onItemClickListener;
this.parentPos = parentPos;
}
@NonNull
@Override
public DeepLinkViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return new DeepLinkViewHolder(LayoutInflater.from(context).inflate(R.layout.inner_bot_msg, parent, false), parentPos);
}
@Override
public void onBindViewHolder(@NonNull final DeepLinkViewHolder holder, final int position) {
DataItem dataItem = dataItemList.get(position);
if (TextUtils.isEmpty(dataItem.getDeeplink())) {
holder.deepLinkText.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);
} else {
holder.deepLinkText.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.ic_right_arrow, 0);
}
if (!TextUtils.isEmpty(dataItem.getText())) {
holder.deepLinkText.setVisibility(View.VISIBLE);
holder.deepLinkText.setText(dataItem.getText());
} else {
holder.deepLinkText.setVisibility(View.GONE);
}
}
@Override
public int getItemCount() {
if (dataItemList != null) {
return dataItemList.size();
} else {
return 0;
}
}
class DeepLinkViewHolder extends RecyclerView.ViewHolder {
private TextView deepLinkText;
DeepLinkViewHolder(View itemView, int parentPos) {
super(itemView);
deepLinkText = itemView.findViewById(R.id.innerDeepLinkMsgText);
if (onItemClickListener != null) {
deepLinkText.setOnClickListener(v -> onItemClickListener.onItemClick(getAdapterPosition(), parentPos));
}
}
}
}
Activity 上的 ItemClickListener 代码:
@Override
public void onItemClick(int childPos, int parentPos) {
if (TextUtils.isEmpty(chatMessageList.get(parentPos).getData().get(childPos).getDeeplink())) {
String message = chatMessageList.get(parentPos).getData().get(childPos).getText();
if (!viewModel.sendMessage(message)) {
setMessage(getString(R.string.error_something_went_wrong), ChatBotManager.UserType.BOT.toString());
} else {
messageListAdapter.onSelected(parentPos);
setMessage(message, ChatBotManager.UserType.USER.toString());
}
} else {
if (TextUtils.equals(chatMessageList.get(parentPos).getData().get(childPos).getDeeplink(), "restart")) {
if (messageListAdapter != null) {
messageListAdapter.clearData();
viewModel.sendMessage("start");
}
} else {
String uri = chatMessageList.get(parentPos).getData().get(childPos).getDeeplink();
Intent newIntent = new Intent(ApplicationClass.getContext(), TalkLinkingActivity.class);
newIntent.setData(Uri.parse(uri));
newIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
newIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(newIntent);
finish();
}
}
}
帮我找出错误,请帮忙!
你为 rvDeepLink 设置了 Visibility 但再也没有显示它,当 view holder 被回收时它仍然消失了
void bindRv(Payload chatMessage, Context context) {
if (chatMessage.getData() != null && !chatMessage.isOptionSelected()) {
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(context);
linearLayoutManager.setOrientation(RecyclerView.VERTICAL);
rvDeepLink.setLayoutManager(linearLayoutManager);
rvDeepLink.setHasFixedSize(true);
DeepLinkAdapter deepLinkAdapter = new DeepLinkAdapter(context, chatMessage.getData(), onItemClickListener, getAdapterPosition());
rvDeepLink.setAdapter(deepLinkAdapter);
rvDeepLink.setVisibility(View.VISIBLE);
} else {
rvDeepLink.setVisibility(View.GONE);
}
}
我正在开发一个聊天机器人,其中父适配器中有两种视图类型,其中 ReceivedMessageViewHolder 具有嵌套的回收器视图,我目前正在通过单击嵌套的回收器视图,但它似乎工作正常。但是当我从底部到底部滚动时,我最终丢失了嵌套回收器视图的最后一项的数据,父项仍在显示但子适配器在滚动时消失了。
我正在为 ParentAdapter、ChildAdapter 和 ItemClick Listener 添加我的代码。请看看并帮助我找出我正在做的错误或如何遇到问题。
ParentAdapter 代码:
public class MessageListAdapter extends RecyclerView.Adapter {
private Context mContext;
private static final int VIEW_TYPE_MESSAGE_SENT = 1;
private static final int VIEW_TYPE_MESSAGE_RECEIVED = 2;
private List<Payload> chatMessageList;
private OnItemClickListener onItemClickListener;
MessageListAdapter(Context context, List<Payload> chatMessageList, OnItemClickListener onItemClickListener) {
this.mContext = context;
this.chatMessageList = chatMessageList;
this.onItemClickListener = onItemClickListener;
}
@Override
public int getItemCount() {
return chatMessageList.size();
}
// Determines the appropriate ViewType according to the sender of the message.
@Override
public int getItemViewType(int position) {
Payload message = chatMessageList.get(position);
if (TextUtils.equals(message.getUserType(), "USER")) {
// If the current user is the sender of the message
return VIEW_TYPE_MESSAGE_SENT;
} else {
// If some other user sent the message
return VIEW_TYPE_MESSAGE_RECEIVED;
}
}
// Inflates the appropriate layout according to the ViewType.
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view;
if (viewType == VIEW_TYPE_MESSAGE_SENT) {
view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_user_msg, parent, false);
return new SentMessageHolder(view);
} else {
view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_bot_msg, parent, false);
return new ReceivedMessageHolder(view);
}
}
// Passes the message object to a ViewHolder so that the contents can be bound to UI.
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
Payload chatMessage = chatMessageList.get(position);
switch (holder.getItemViewType()) {
case VIEW_TYPE_MESSAGE_SENT:
((SentMessageHolder) holder).bind(chatMessage.getMessage(), getFormattedTime());
break;
case VIEW_TYPE_MESSAGE_RECEIVED:
((ReceivedMessageHolder) holder).bind(chatMessage.getMessage(), getFormattedTime());
((ReceivedMessageHolder) holder).bindRv(chatMessage, mContext);
break;
}
}
private static class SentMessageHolder extends RecyclerView.ViewHolder {
TextView txtViewChatMsgUser;
TextView txtViewDateTimeUser;
SentMessageHolder(View itemView) {
super(itemView);
txtViewChatMsgUser = itemView.findViewById(R.id.txtViewChatMsgUser);
txtViewDateTimeUser = itemView.findViewById(R.id.txtViewDateTimeUser);
}
void bind(String message, String time) {
txtViewChatMsgUser.setText(message);
txtViewDateTimeUser.setText(time);
}
}
private class ReceivedMessageHolder extends RecyclerView.ViewHolder {
TextView txtViewChatMsgBot;
RecyclerView rvDeepLink;
TextView txtViewDateTimeBot;
ReceivedMessageHolder(View itemView) {
super(itemView);
txtViewChatMsgBot = itemView.findViewById(R.id.txtViewChatMsgBot);
rvDeepLink = itemView.findViewById(R.id.itemRvDeepLink);
txtViewDateTimeBot = itemView.findViewById(R.id.txtViewDateTimeBot);
}
void bind(String message, String time) {
txtViewChatMsgBot.setText(message);
txtViewDateTimeBot.setText(time);
}
void bindRv(Payload chatMessage, Context context) {
if (chatMessage.getData() != null && !chatMessage.isOptionSelected()) {
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(context);
linearLayoutManager.setOrientation(RecyclerView.VERTICAL);
rvDeepLink.setLayoutManager(linearLayoutManager);
rvDeepLink.setHasFixedSize(true);
DeepLinkAdapter deepLinkAdapter = new DeepLinkAdapter(context, chatMessage.getData(), onItemClickListener, getAdapterPosition());
rvDeepLink.setAdapter(deepLinkAdapter);
} else {
rvDeepLink.setVisibility(View.GONE);
}
}
}
private String getFormattedTime() {
SimpleDateFormat dateFormat = new SimpleDateFormat("hh.mm aa", Locale.ENGLISH);
return dateFormat.format(new Date());
}
void onSelected(int position) {
chatMessageList.get(position).setOptionSelected(true);
notifyItemChanged(position);
}
}
子适配器代码:
public class DeepLinkAdapter extends RecyclerView.Adapter<DeepLinkAdapter.DeepLinkViewHolder> {
private List<DataItem> dataItemList;
private Context context;
private OnItemClickListener onItemClickListener;
private int parentPos;
DeepLinkAdapter(Context context, List<DataItem> dataItemList, OnItemClickListener onItemClickListener, int parentPos) {
this.context = context;
this.dataItemList = dataItemList;
this.onItemClickListener = onItemClickListener;
this.parentPos = parentPos;
}
@NonNull
@Override
public DeepLinkViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return new DeepLinkViewHolder(LayoutInflater.from(context).inflate(R.layout.inner_bot_msg, parent, false), parentPos);
}
@Override
public void onBindViewHolder(@NonNull final DeepLinkViewHolder holder, final int position) {
DataItem dataItem = dataItemList.get(position);
if (TextUtils.isEmpty(dataItem.getDeeplink())) {
holder.deepLinkText.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);
} else {
holder.deepLinkText.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.ic_right_arrow, 0);
}
if (!TextUtils.isEmpty(dataItem.getText())) {
holder.deepLinkText.setVisibility(View.VISIBLE);
holder.deepLinkText.setText(dataItem.getText());
} else {
holder.deepLinkText.setVisibility(View.GONE);
}
}
@Override
public int getItemCount() {
if (dataItemList != null) {
return dataItemList.size();
} else {
return 0;
}
}
class DeepLinkViewHolder extends RecyclerView.ViewHolder {
private TextView deepLinkText;
DeepLinkViewHolder(View itemView, int parentPos) {
super(itemView);
deepLinkText = itemView.findViewById(R.id.innerDeepLinkMsgText);
if (onItemClickListener != null) {
deepLinkText.setOnClickListener(v -> onItemClickListener.onItemClick(getAdapterPosition(), parentPos));
}
}
}
}
Activity 上的 ItemClickListener 代码:
@Override
public void onItemClick(int childPos, int parentPos) {
if (TextUtils.isEmpty(chatMessageList.get(parentPos).getData().get(childPos).getDeeplink())) {
String message = chatMessageList.get(parentPos).getData().get(childPos).getText();
if (!viewModel.sendMessage(message)) {
setMessage(getString(R.string.error_something_went_wrong), ChatBotManager.UserType.BOT.toString());
} else {
messageListAdapter.onSelected(parentPos);
setMessage(message, ChatBotManager.UserType.USER.toString());
}
} else {
if (TextUtils.equals(chatMessageList.get(parentPos).getData().get(childPos).getDeeplink(), "restart")) {
if (messageListAdapter != null) {
messageListAdapter.clearData();
viewModel.sendMessage("start");
}
} else {
String uri = chatMessageList.get(parentPos).getData().get(childPos).getDeeplink();
Intent newIntent = new Intent(ApplicationClass.getContext(), TalkLinkingActivity.class);
newIntent.setData(Uri.parse(uri));
newIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
newIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(newIntent);
finish();
}
}
}
帮我找出错误,请帮忙!
你为 rvDeepLink 设置了 Visibility 但再也没有显示它,当 view holder 被回收时它仍然消失了
void bindRv(Payload chatMessage, Context context) {
if (chatMessage.getData() != null && !chatMessage.isOptionSelected()) {
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(context);
linearLayoutManager.setOrientation(RecyclerView.VERTICAL);
rvDeepLink.setLayoutManager(linearLayoutManager);
rvDeepLink.setHasFixedSize(true);
DeepLinkAdapter deepLinkAdapter = new DeepLinkAdapter(context, chatMessage.getData(), onItemClickListener, getAdapterPosition());
rvDeepLink.setAdapter(deepLinkAdapter);
rvDeepLink.setVisibility(View.VISIBLE);
} else {
rvDeepLink.setVisibility(View.GONE);
}
}