如何阻止RecyclerView项目显示乱序

时间:2019-01-07 18:53:20

标签: android android-recyclerview

我正在使用RecyclerView来显示来自用户和机器人的消息,但是在滚动大约10条消息后,RecyclerView的项目显示不正常。

我从LinearLayoutManager中删除了我的代码中的setStackFromEnd()setReverseLayout(),以防引起任何问题,但仍不能解决问题。我还添加了holder.setIsRecyclable(false);行,尽管行很有效,但我不想使用该解决方案,因为它违反了RecyclerView的目的。

获取用户响应,将响应添加到消息列表中,生成回复,并拨打电话updateUI()

public void respond(String input) {
    int position = getMessagePosition();
    Log.d(CHAT_FRAGMENT_TAG, "Received Message: " + input);
    String reply = mBot.reply("user", input);
    Log.d(CHAT_FRAGMENT_TAG, "Bot Reply: " + reply);
    mMessages.add(new Message(reply, Message.BOT_MESSAGE, messagePosition()));
    updateUI(position);
    Log.d(CHAT_FRAGMENT_TAG, "mMessages List: " + mMessages.get(position).getText());
}

updateUI()

public void updateUI(int insertPosition) {
    if (mAdapter == null) {
        mAdapter = new MessageAdapter();
        mRecyclerView.setAdapter(mAdapter);
    } else
        mAdapter.notifyItemInserted(insertPosition);
}

onBindViewHolder()

@Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        Message message = mMessages.get(position);

        if (getItemViewType(position) == Message.USER_MESSAGE)
            ((UserMessageHolder) holder).bind(message);
        else
            ((BotMessageHolder) holder).bind(message);
    }

bind()

public void bind(Message message) {
        mBotTextView.setText(message.getText());
    }

messagePosition()getMessagePosition()

    public static int messagePosition() {
    //A convenience function to get the current position and increment it as well for the next array element.
    int returnValue = mMessagePosition;
    mMessagePosition++;
    return returnValue;
}

public static int getMessagePosition() {
    return mMessagePosition;
}

EditText上有一个onClick()方法,该方法接受用户的响应并调用respond()方法。 respond()方法得到机器人的答复,并调用updateUI()方法以使适配器知道由于添加了新消息(来自用户的一条消息和来自机器人的一条消息),该数组更大。在大约有10条消息并且用户需要滚动之前,此过程可以正常进行。从那时起,重复或不正确地将邮件错误地重新加载到屏幕上。

2 个答案:

答案 0 :(得分:1)

如果消息出现在错误的位置或根本没有出现问题,则潜在的问题是您的数据集没有适配器认为应该的数据。

想象一下,您有一个字符串列表["A", "B", "C"]。您向其中添加了两条消息,但是仅通知适配器已添加一条消息。适配器认为列表现在是["A", "B", "C", "D"],但实际上是["A", "B", "C", "D", "E"]。最终将导致问题。

在您发布的代码中,您只有一个notifyItemInserted()调用(用于漫游器对用户消息的响应)。但是,您已经描述了一个工作流程,其中包括添加用户消息和漫游器回复。那使我认为您错过了所需的notify通话。

您可以将所有对notifyItemInserted()的呼叫替换为notifyDataSetChanged(),看看是否可以解决问题。通常,最好使用notifyItemInserted(),但是如果这可以解决问题,那么您就会知道问题是您错过了{ {1}}致电给您。然后,您可以非常仔细地检查代码,并确保在更改notify的任何时间都通知适配器。

答案 1 :(得分:1)

我遇到了同样的问题。考虑将所有对话存储在某个地方,例如,我将其存储在对话类中

//列表适配器

class MessagesListAdapter : RecyclerView.Adapter<MessageViewHolder>() {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MessageViewHolder = MessageViewHolder(LayoutInflater.from(parent.context).inflate(viewType, parent, false))
    override fun getItemCount(): Int = Conversation.getCount()
    override fun reloadDataSet() {}
    override fun onBindViewHolder(holder: MessageViewHolder, position: Int) {
        holder.bind(Conversation.getMessage(position))
    }

    override fun getItemViewType(position: Int): Int = when (Conversation.getMessage(position).response) {
        true -> R.layout.message_response
        false -> R.layout.message_sent
    }
}

//消息持有人

 class MessageViewHolder(private var item: View) : RecyclerView.ViewHolder(item) {

    fun bind(message: TextMessage) {
        if (message.response) {
            item.findViewById<TextView>(R.id.tv_response_bubble).text = message.text
        } else {
            item.findViewById<TextView>(R.id.tv_user_bubble).text = message.text
        }
    }
}

//活动分类

  class ChatActivity : AppCompatActivity() {

    private val listAdapter = MessagesListAdapter()
    private lateinit var messagesListView: RecyclerView

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_chat)
        messagesListView = findViewById(R.id.recyclerView)
        messagesListView.adapter = listAdapter

        val layoutManager = LinearLayoutManager(this)
        //For messages to appear from bottom to top
        layoutManager.stackFromEnd = true
        messagesListView.layoutManager = layoutManager

    }

    //Code you call from activity to update the list
    private fun addMessage(message: TextMessage) {
        if (!message.isNullOrBlank()) {
            Conversation.add(message)
            listAdapter.notifyItemChanged(Conversation.getCount() - 1)
            messagesListView.smoothScrollToPosition(Conversation.getCount() - 1)

        }
    }
}

//Conversation class
public class Conversation {
    private static List<TextMessage> currentConversation;

    public static void clear() {
        currentConversation = new ArrayList<>();
    }

    public static void add(final TextMessage message) {
        if (currentConversation == null) {
            clear();
        }
        currentConversation.add(message);
    }

    static TextMessage getMessage(final int pos) {
        if (currentConversation == null) {
            return null;
        }
        return currentConversation.get(pos);
    }

    static int getCount() {
        return currentConversation == null ? 0 : currentConversation.size();
    }
}