RecyclerView onBindViewHolder 被无限次调用单个项目
RecyclerView onBindViewHolder is being called unlimited time for single item
我正在构建一个聊天应用程序,在 聊天片段 我目前有一个聊天,其中有一条消息。问题是针对单个项目连续调用 onBindViewHolder
。我发现了一个相关问题 ,它说问题是由 itemview
的布局参数引起的但是我对 itemview
的布局参数没有做任何事情。由于连续调用 onBindViewHolder
用于打开聊天的点击侦听器 activity 也无法正常工作。查看 Logcat
详细信息:
2019-03-08 00:48:54.464 1672-1672/com.invogen.messagingapp E/ChatAdapter: Message Key = -L_OWO_jaN6ggbeoAlmI
2019-03-08 00:48:54.474 1672-1672/com.invogen.messagingapp E/ChatAdapter: ChatPath = https://messagingapp-db3e5.firebaseio.com/Chats/-L_OWO_fra0oDMflLMTE/messages
2019-03-08 00:48:54.480 1672-1672/com.invogen.messagingapp E/ChatAdapter: Message Key = -L_OWO_jaN6ggbeoAlmI
2019-03-08 00:48:54.490 1672-1672/com.invogen.messagingapp E/ChatAdapter: ChatPath = https://messagingapp-db3e5.firebaseio.com/Chats/-L_OWO_fra0oDMflLMTE/messages
2019-03-08 00:48:54.497 1672-1672/com.invogen.messagingapp E/ChatAdapter: Message Key = -L_OWO_jaN6ggbeoAlmI
2019-03-08 00:48:54.507 1672-1672/com.invogen.messagingapp E/ChatAdapter: ChatPath = https://messagingapp-db3e5.firebaseio.com/Chats/-L_OWO_fra0oDMflLMTE/messages
2019-03-08 00:48:54.515 1672-1672/com.invogen.messagingapp E/ChatAdapter: Message Key = -L_OWO_jaN6ggbeoAlmI
2019-03-08 00:48:54.524 1672-1672/com.invogen.messagingapp E/ChatAdapter: ChatPath = https://messagingapp-db3e5.firebaseio.com/Chats/-L_OWO_fra0oDMflLMTE/messages
2019-03-08 00:48:54.532 1672-1672/com.invogen.messagingapp E/ChatAdapter: Message Key = -L_OWO_jaN6ggbeoAlmI
2019-03-08 00:48:54.540 1672-1672/com.invogen.messagingapp E/ChatAdapter: ChatPath = https://messagingapp-db3e5.firebaseio.com/Chats/-L_OWO_fra0oDMflLMTE/messages
2019-03-08 00:48:54.552 1672-1672/com.invogen.messagingapp E/ChatAdapter: Message Key = -L_OWO_jaN6ggbeoAlmI
2019-03-08 00:48:54.558 1672-1672/com.invogen.messagingapp E/ChatAdapter: ChatPath = https://messagingapp-db3e5.firebaseio.com/Chats/-L_OWO_fra0oDMflLMTE/messages
2019-03-08 00:48:54.568 1672-1672/com.invogen.messagingapp E/ChatAdapter: Message Key = -L_OWO_jaN6ggbeoAlmI
2019-03-08 00:48:54.575 1672-1672/com.invogen.messagingapp E/ChatAdapter: ChatPath = https://messagingapp-db3e5.firebaseio.com/Chats/-L_OWO_fra0oDMflLMTE/messages
2019-03-08 00:48:54.583 1672-1672/com.invogen.messagingapp E/ChatAdapter: Message Key = -L_OWO_jaN6ggbeoAlmI
2019-03-08 00:48:54.591 1672-1672/com.invogen.messagingapp E/ChatAdapter: ChatPath = https://messagingapp-db3e5.firebaseio.com/Chats/-L_OWO_fra0oDMflLMTE/messages
2019-03-08 00:48:54.600 1672-1672/com.invogen.messagingapp E/ChatAdapter: Message Key = -L_OWO_jaN6ggbeoAlmI
2019-03-08 00:48:54.608 1672-1672/com.invogen.messagingapp E/ChatAdapter: ChatPath = https://messagingapp-db3e5.firebaseio.com/Chats/-L_OWO_fra0oDMflLMTE/messages
2019-03-08 00:48:54.616 1672-1672/com.invogen.messagingapp E/ChatAdapter: Message Key = -L_OWO_jaN6ggbeoAlmI
2019-03-08 00:48:54.624 1672-1672/com.invogen.messagingapp E/ChatAdapter: ChatPath = https://messagingapp-db3e5.firebaseio.com/Chats/-L_OWO_fra0oDMflLMTE/messages
2019-03-08 00:48:54.631 1672-1672/com.invogen.messagingapp E/ChatAdapter: Message Key = -L_OWO_jaN6ggbeoAlmI
2019-03-08 00:48:54.642 1672-1672/com.invogen.messagingapp E/ChatAdapter: ChatPath = https://messagingapp-db3e5.firebaseio.com/Chats/-L_OWO_fra0oDMflLMTE/messages
2019-03-08 00:48:54.649 1672-1672/com.invogen.messagingapp E/ChatAdapter: Message Key = -L_OWO_jaN6ggbeoAlmI
2019-03-08 00:48:54.658 1672-1672/com.invogen.messagingapp E/ChatAdapter: ChatPath = https://messagingapp-db3e5.firebaseio.com/Chats/-L_OWO_fra0oDMflLMTE/messages
2019-03-08 00:48:54.740 1672-1672/com.invogen.messagingapp E/ChatAdapter: Message Key = -L_OWO_jaN6ggbeoAlmI
此过程在我退出应用程序之前不会停止。这是我的 firebase database
这个聊天节点的结构
下面是我的聊天片段代码,它调用 ChatAdapter
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_chats, container, false);
this.mContext = view.getContext();
initViews(view);
mChatsDBReference = FirebaseDatabase.getInstance().getReference().child(AppConstants.CHATS_NODE);
fabCreate.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// Floating Action Button's Action code here for creating new chat group
}
});
LinearLayoutManager layoutManager = new LinearLayoutManager(getContext());
mRecyclerView.setLayoutManager(layoutManager);
mRecyclerView.setAdapter(new ChatAdapter(chatRoomChatsList, chatRoomKeysList));
mChatsDBReference.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
chatRoomChatsList.clear();
chatRoomKeysList.clear();
if (dataSnapshot.exists()) {
Log.e(TAG, "Snapshot Exits\nValue = " + dataSnapshot.toString());
for (DataSnapshot ds : dataSnapshot.getChildren()) {
Chats chat = ds.getValue(Chats.class);
Log.e(TAG, "Chat Key = " + ds.getKey() + "\n DataSnapshot = " + ds.toString());
chatRoomChatsList.add(chat);
chatRoomKeysList.add(ds.getKey());
}
}
mRecyclerView.getAdapter().notifyDataSetChanged();
}
@Override
public void onCancelled(@NonNull DatabaseError databaseError) {
}
});
return view;
}
这是我的ChatAdapter
class
public class ChatAdapter extends RecyclerView.Adapter<ChatViewHolder> {
private String TAG = "ChatAdapter";
private List<Chats> chatRoomChatsList;
private Context mContext;
// private String pushKey;
private List<String> chatRoomChatsKeyList;
private List<FriendlyMessage> messageList;
public ChatAdapter(List<Chats> chatList, List<String> chatRoomChatsKeyList) {
this.chatRoomChatsList = chatList;
// this.pushKey = pushKey;
this.chatRoomChatsKeyList = chatRoomChatsKeyList;
}
@NonNull
@Override
public ChatViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int itemViewType) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.chats_layout,
viewGroup, false);
Log.e(TAG, "onCreateView LayoutId = " + itemViewType + " Inside MyLayout");
return new ChatViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull final ChatViewHolder holder, int position) {
mContext = holder.chatTitleTV.getContext();
int pos = holder.getAdapterPosition();
setupLastMessageData(holder);
Chats chat = chatRoomChatsList.get(pos);
String chatTitle = chat.getChatName();
holder.chatTitleTV.setText(chatTitle);
holder.avatarTV.setText(chatTitle);
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String pushkey = chatRoomChatsKeyList.get(holder.getAdapterPosition());
Log.e(TAG, "pushKey = " + pushkey);
Bundle bundle = new Bundle();
bundle.putString("pushKey", pushkey);
Intent intent = new Intent(mContext, ChatMessagesActivity.class);
intent.putExtras(bundle);
mContext.startActivity(intent);
}
});
}
private void setupLastMessageData(final ChatViewHolder holder) {
DatabaseReference mSingleChatReference =
FirebaseDatabase.getInstance().getReference()
.child(AppConstants.CHATS_NODE)
.child(chatRoomChatsKeyList.get(holder.getAdapterPosition()))
.child("messages");
Log.e(TAG, "ChatPath = " + mSingleChatReference);
mSingleChatReference.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
messageList = new ArrayList<>();
if (dataSnapshot.exists()) {
for (DataSnapshot ds : dataSnapshot.getChildren()) {
FriendlyMessage msg = ds.getValue(FriendlyMessage.class);
Log.e(TAG, "Message Key = " + ds.getKey());
messageList.add(msg);
}
}
holder.lastMessageTV.setText(messageList.get(messageList.size() - 1).getMsgText());
holder.timeTV.setText(messageList.get(messageList.size() - 1).getMsgDate());
notifyDataSetChanged();
}
@Override
public void onCancelled(@NonNull DatabaseError databaseError) {
}
});
}
@Override
public int getItemCount() {
return chatRoomChatsList.size();
}
}
如果需要任何其他信息,请告诉我。任何帮助将不胜感激。
在您的 createView() 中,您正在调用 notifyDataSetChanged(),这会导致 RecyclerView 重新绑定并更新其所有内容。该过程的一部分包括调用 adapter.onBindViewHolder() 以将数据集绑定到构成列表的各个项目视图。但是在 adapter.onBindViewHolder() 中,您调用了 setupLastMessageData() ,它在内部再次调用 notifyDataSetChanged() ,它再次开始循环。这会创建 notify->bind->notify->bind
的无限循环
我的建议是让那些 firebase 侦听器位于适配器外部,侦听数据结构的必要更改和更新,并通过一次调用 notifyDataSetChanged() 将这些更改传递给适配器。如果您能够确定实际添加或更改了哪些消息,您甚至可以通过不调用 notifyDataSetChanged() 并从适配器调用更细化的 notifyXXX methods() 来提高效率。
我正在构建一个聊天应用程序,在 聊天片段 我目前有一个聊天,其中有一条消息。问题是针对单个项目连续调用 onBindViewHolder
。我发现了一个相关问题 itemview
的布局参数引起的但是我对 itemview
的布局参数没有做任何事情。由于连续调用 onBindViewHolder
用于打开聊天的点击侦听器 activity 也无法正常工作。查看 Logcat
详细信息:
2019-03-08 00:48:54.464 1672-1672/com.invogen.messagingapp E/ChatAdapter: Message Key = -L_OWO_jaN6ggbeoAlmI
2019-03-08 00:48:54.474 1672-1672/com.invogen.messagingapp E/ChatAdapter: ChatPath = https://messagingapp-db3e5.firebaseio.com/Chats/-L_OWO_fra0oDMflLMTE/messages
2019-03-08 00:48:54.480 1672-1672/com.invogen.messagingapp E/ChatAdapter: Message Key = -L_OWO_jaN6ggbeoAlmI
2019-03-08 00:48:54.490 1672-1672/com.invogen.messagingapp E/ChatAdapter: ChatPath = https://messagingapp-db3e5.firebaseio.com/Chats/-L_OWO_fra0oDMflLMTE/messages
2019-03-08 00:48:54.497 1672-1672/com.invogen.messagingapp E/ChatAdapter: Message Key = -L_OWO_jaN6ggbeoAlmI
2019-03-08 00:48:54.507 1672-1672/com.invogen.messagingapp E/ChatAdapter: ChatPath = https://messagingapp-db3e5.firebaseio.com/Chats/-L_OWO_fra0oDMflLMTE/messages
2019-03-08 00:48:54.515 1672-1672/com.invogen.messagingapp E/ChatAdapter: Message Key = -L_OWO_jaN6ggbeoAlmI
2019-03-08 00:48:54.524 1672-1672/com.invogen.messagingapp E/ChatAdapter: ChatPath = https://messagingapp-db3e5.firebaseio.com/Chats/-L_OWO_fra0oDMflLMTE/messages
2019-03-08 00:48:54.532 1672-1672/com.invogen.messagingapp E/ChatAdapter: Message Key = -L_OWO_jaN6ggbeoAlmI
2019-03-08 00:48:54.540 1672-1672/com.invogen.messagingapp E/ChatAdapter: ChatPath = https://messagingapp-db3e5.firebaseio.com/Chats/-L_OWO_fra0oDMflLMTE/messages
2019-03-08 00:48:54.552 1672-1672/com.invogen.messagingapp E/ChatAdapter: Message Key = -L_OWO_jaN6ggbeoAlmI
2019-03-08 00:48:54.558 1672-1672/com.invogen.messagingapp E/ChatAdapter: ChatPath = https://messagingapp-db3e5.firebaseio.com/Chats/-L_OWO_fra0oDMflLMTE/messages
2019-03-08 00:48:54.568 1672-1672/com.invogen.messagingapp E/ChatAdapter: Message Key = -L_OWO_jaN6ggbeoAlmI
2019-03-08 00:48:54.575 1672-1672/com.invogen.messagingapp E/ChatAdapter: ChatPath = https://messagingapp-db3e5.firebaseio.com/Chats/-L_OWO_fra0oDMflLMTE/messages
2019-03-08 00:48:54.583 1672-1672/com.invogen.messagingapp E/ChatAdapter: Message Key = -L_OWO_jaN6ggbeoAlmI
2019-03-08 00:48:54.591 1672-1672/com.invogen.messagingapp E/ChatAdapter: ChatPath = https://messagingapp-db3e5.firebaseio.com/Chats/-L_OWO_fra0oDMflLMTE/messages
2019-03-08 00:48:54.600 1672-1672/com.invogen.messagingapp E/ChatAdapter: Message Key = -L_OWO_jaN6ggbeoAlmI
2019-03-08 00:48:54.608 1672-1672/com.invogen.messagingapp E/ChatAdapter: ChatPath = https://messagingapp-db3e5.firebaseio.com/Chats/-L_OWO_fra0oDMflLMTE/messages
2019-03-08 00:48:54.616 1672-1672/com.invogen.messagingapp E/ChatAdapter: Message Key = -L_OWO_jaN6ggbeoAlmI
2019-03-08 00:48:54.624 1672-1672/com.invogen.messagingapp E/ChatAdapter: ChatPath = https://messagingapp-db3e5.firebaseio.com/Chats/-L_OWO_fra0oDMflLMTE/messages
2019-03-08 00:48:54.631 1672-1672/com.invogen.messagingapp E/ChatAdapter: Message Key = -L_OWO_jaN6ggbeoAlmI
2019-03-08 00:48:54.642 1672-1672/com.invogen.messagingapp E/ChatAdapter: ChatPath = https://messagingapp-db3e5.firebaseio.com/Chats/-L_OWO_fra0oDMflLMTE/messages
2019-03-08 00:48:54.649 1672-1672/com.invogen.messagingapp E/ChatAdapter: Message Key = -L_OWO_jaN6ggbeoAlmI
2019-03-08 00:48:54.658 1672-1672/com.invogen.messagingapp E/ChatAdapter: ChatPath = https://messagingapp-db3e5.firebaseio.com/Chats/-L_OWO_fra0oDMflLMTE/messages
2019-03-08 00:48:54.740 1672-1672/com.invogen.messagingapp E/ChatAdapter: Message Key = -L_OWO_jaN6ggbeoAlmI
此过程在我退出应用程序之前不会停止。这是我的 firebase database
这个聊天节点的结构
下面是我的聊天片段代码,它调用 ChatAdapter
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_chats, container, false);
this.mContext = view.getContext();
initViews(view);
mChatsDBReference = FirebaseDatabase.getInstance().getReference().child(AppConstants.CHATS_NODE);
fabCreate.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// Floating Action Button's Action code here for creating new chat group
}
});
LinearLayoutManager layoutManager = new LinearLayoutManager(getContext());
mRecyclerView.setLayoutManager(layoutManager);
mRecyclerView.setAdapter(new ChatAdapter(chatRoomChatsList, chatRoomKeysList));
mChatsDBReference.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
chatRoomChatsList.clear();
chatRoomKeysList.clear();
if (dataSnapshot.exists()) {
Log.e(TAG, "Snapshot Exits\nValue = " + dataSnapshot.toString());
for (DataSnapshot ds : dataSnapshot.getChildren()) {
Chats chat = ds.getValue(Chats.class);
Log.e(TAG, "Chat Key = " + ds.getKey() + "\n DataSnapshot = " + ds.toString());
chatRoomChatsList.add(chat);
chatRoomKeysList.add(ds.getKey());
}
}
mRecyclerView.getAdapter().notifyDataSetChanged();
}
@Override
public void onCancelled(@NonNull DatabaseError databaseError) {
}
});
return view;
}
这是我的ChatAdapter
class
public class ChatAdapter extends RecyclerView.Adapter<ChatViewHolder> {
private String TAG = "ChatAdapter";
private List<Chats> chatRoomChatsList;
private Context mContext;
// private String pushKey;
private List<String> chatRoomChatsKeyList;
private List<FriendlyMessage> messageList;
public ChatAdapter(List<Chats> chatList, List<String> chatRoomChatsKeyList) {
this.chatRoomChatsList = chatList;
// this.pushKey = pushKey;
this.chatRoomChatsKeyList = chatRoomChatsKeyList;
}
@NonNull
@Override
public ChatViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int itemViewType) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.chats_layout,
viewGroup, false);
Log.e(TAG, "onCreateView LayoutId = " + itemViewType + " Inside MyLayout");
return new ChatViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull final ChatViewHolder holder, int position) {
mContext = holder.chatTitleTV.getContext();
int pos = holder.getAdapterPosition();
setupLastMessageData(holder);
Chats chat = chatRoomChatsList.get(pos);
String chatTitle = chat.getChatName();
holder.chatTitleTV.setText(chatTitle);
holder.avatarTV.setText(chatTitle);
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String pushkey = chatRoomChatsKeyList.get(holder.getAdapterPosition());
Log.e(TAG, "pushKey = " + pushkey);
Bundle bundle = new Bundle();
bundle.putString("pushKey", pushkey);
Intent intent = new Intent(mContext, ChatMessagesActivity.class);
intent.putExtras(bundle);
mContext.startActivity(intent);
}
});
}
private void setupLastMessageData(final ChatViewHolder holder) {
DatabaseReference mSingleChatReference =
FirebaseDatabase.getInstance().getReference()
.child(AppConstants.CHATS_NODE)
.child(chatRoomChatsKeyList.get(holder.getAdapterPosition()))
.child("messages");
Log.e(TAG, "ChatPath = " + mSingleChatReference);
mSingleChatReference.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
messageList = new ArrayList<>();
if (dataSnapshot.exists()) {
for (DataSnapshot ds : dataSnapshot.getChildren()) {
FriendlyMessage msg = ds.getValue(FriendlyMessage.class);
Log.e(TAG, "Message Key = " + ds.getKey());
messageList.add(msg);
}
}
holder.lastMessageTV.setText(messageList.get(messageList.size() - 1).getMsgText());
holder.timeTV.setText(messageList.get(messageList.size() - 1).getMsgDate());
notifyDataSetChanged();
}
@Override
public void onCancelled(@NonNull DatabaseError databaseError) {
}
});
}
@Override
public int getItemCount() {
return chatRoomChatsList.size();
}
}
如果需要任何其他信息,请告诉我。任何帮助将不胜感激。
在您的 createView() 中,您正在调用 notifyDataSetChanged(),这会导致 RecyclerView 重新绑定并更新其所有内容。该过程的一部分包括调用 adapter.onBindViewHolder() 以将数据集绑定到构成列表的各个项目视图。但是在 adapter.onBindViewHolder() 中,您调用了 setupLastMessageData() ,它在内部再次调用 notifyDataSetChanged() ,它再次开始循环。这会创建 notify->bind->notify->bind
的无限循环我的建议是让那些 firebase 侦听器位于适配器外部,侦听数据结构的必要更改和更新,并通过一次调用 notifyDataSetChanged() 将这些更改传递给适配器。如果您能够确定实际添加或更改了哪些消息,您甚至可以通过不调用 notifyDataSetChanged() 并从适配器调用更细化的 notifyXXX methods() 来提高效率。