首页 > 解决方案 > 在嵌套 RecyclerView 中滚动时丢失数据

问题描述

我正在开发一个聊天机器人,其中父适配器中有两种视图类型,其中 ReceivedMessageViewHolder 具有嵌套的回收器视图,我目前正在删除嵌套回收器视图的可见性,单击嵌套回收器视图中的任何项目,但是和它似乎工作正常。但是当我从下到上滚动时,我最终会丢失嵌套回收器视图的最后一项中的数据,父项仍在显示,但子适配器在滚动时消失了。

我正在为 ParentAdapter、ChildAdapter 和 ItemClick 侦听器添加我的代码。请看一下并帮助我找出我正在做的错误或如何遇到问题。

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();
            }
        }
    }

帮我找出我的错误,请帮助!

标签: androidandroid-recyclerviewnestedrecyclerview

解决方案


您为 rvDeepLink 设置了可见性,但不再显示它,当视图持有者被回收时它仍然消失

      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);
            }
        }

推荐阅读