Android Firebase中ChildEventListener的onChildAdded重复触发问题
我看了你的代码,发现问题核心是重复绑定了ChildEventListener,这就是每条消息的onChildAdded都会被调用两次的原因。
问题分析
你在getLastMessage()方法里,已经通过queryLastMessage.addChildEventListener(...)给查询对象绑定了一个ChildEventListener,并且把这个listener返回了。但之后你又在初始化代码里,把这个返回的listener再次绑定到了chatRoomLastMessageUpdateReference这个DatabaseReference上:
chatRoomLastMessageUpdateReference.addChildEventListener(chatRoomLastMessageChildListener);
这就导致同一个listener被绑定到了两个不同对象(Query和DatabaseReference)上,每次有新消息时,两个绑定都会触发onChildAdded,自然就出现了重复调用的情况。
修复步骤
1. 移除重复的监听绑定代码
直接删掉初始化代码里的这一行:
chatRoomLastMessageUpdateReference.addChildEventListener(chatRoomLastMessageChildListener);
因为getLastMessage()内部已经给queryLastMessage这个查询对象绑定了监听,不需要再给原DatabaseReference重复绑定。
2. 调整监听解绑逻辑
现在你的listener是绑定在Query对象上的,所以解绑时需要用这个Query对象来移除监听,而不是原DatabaseReference。可以把Query设为类的成员变量来实现:
首先修改getLastMessage()方法,保存Query引用:
// 新增类成员变量 private Query mLastMessageQuery; public ChildEventListener getLastMessage(final AdapterChat mAdapterChat, final DatabaseReference pollRoomLastMessageUpdateReference, final RecyclerView mRecyclerChat) { mLastMessageQuery = pollRoomLastMessageUpdateReference.orderByKey().limitToLast(1); ChildEventListener childEventListener = new ChildEventListener() { @Override public void onChildAdded(DataSnapshot dataSnapshot, String s) { Message message = dataSnapshot.getValue(Message.class); Log.d("message", "onChildAdded: " + message.getMessage()); mAdapterChat.updateLastMessage(message); mRecyclerChat.getLayoutManager().scrollToPosition(mAdapterChat.getMessagesObekt().size() - 1); } @Override public void onChildChanged(DataSnapshot dataSnapshot, String s) { } @Override public void onChildRemoved(DataSnapshot dataSnapshot) { } @Override public void onChildMoved(DataSnapshot dataSnapshot, String s) { } @Override public void onCancelled(DatabaseError databaseError) { } }; mLastMessageQuery.addChildEventListener(childEventListener); return childEventListener; }
然后修改解绑代码,用Query对象移除监听:
@Override protected void onDestroy() { super.onDestroy(); if (chatRoomLastMessageChildListener != null && mLastMessageQuery != null) { mLastMessageQuery.removeEventListener(chatRoomLastMessageChildListener); } }
3. 验证效果
这样修改后,每条新消息只会触发一次onChildAdded,同时也能正常完成监听解绑,避免内存泄漏问题。
内容的提问来源于stack exchange,提问作者NoName

