我正在使用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条消息并且用户需要滚动之前,此过程可以正常进行。从那时起,重复或不正确地将邮件错误地重新加载到屏幕上。
答案 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();
}
}