我在Activity的onCreate方法中设置了一个值事件监听器。在该方法中,我将数据记录到控制台。我打开了活动,一切正常。但是,如果我关闭活动并更改数据,它仍会被调用,我可以在日志中看到它。
因此,如果我打开该活动说5次,则每次更新时都会看到5条日志消息。
我们是否有任何解决方案可以提供该活动的上下文,以便听众在活动结束时死亡。
rootRef.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
Log.v(TAG, "Data Changed in Activity2");
}
@Override
public void onCancelled(DatabaseError databaseError) {
}
});
我还需要在RecyclerView中提供太多的值监听器。滚动后,它还会导致多个值更改的事件调用。因为它在现有位置绑定了一个新的谎言者,并且没有从onViewRecycled
方法中删除的引用。因此,它们被多次调用并在屏幕上随机更改数据。
使用上下文可以更轻松地设置值事件侦听器。有没有办法跟踪所有听众?也没有方法可以让听众参考。
答案 0 :(得分:5)
由于目前无法向听众提供上下文,因此需要跟踪所有附加的侦听器并将其删除,如David在答案中所示:https://stackoverflow.com/a/33782474/1820644
为了管理RecyclerView
内的值监听器,我提出了一个运行良好的解决方案。我正在使用FirebaseUI的RecyclerView,但该解决方案应适用于每个RecyclerView
。
第1步:首先在您的活动中创建全局Map<String,ValueEventListener>
:
HashMap<String, ValueEventListener> mRecyclerViewFirebaseListeners = new HashMap<>();
第2步:在ValueEventListener
(在firebaseUI中)或populateViewHolder
绑定onBindViewHodler
,然后将其添加到我们的地图mRecyclerViewFirebaseListeners
。另外,使用键
Tag
来查看持有人
protected void populateViewHolder(final ViewHolder viewHolder,
Boolean model, int position) {
Log.v(TAG, "Populating viewHolder for position: " + position);
// Get the key and add listener
String key = this.getRef(position).getKey();
ValueEventListener listener = mRootRef.child("events").child(key)
.addValueEventListener(new ValueEventListener() {
public void onDataChange(DataSnapshot dataSnapshot) {
Log.v(TAG, "Event Data Change");
// ...
}
@Override
public void onCancelled(DatabaseError databaseError) {
Log.v(TAG, databaseError.getMessage());
}
});
Log.v(TAG, "Listener set for event key: " + key + " (position: " +
position + ")");
// Add to our map and set tag on view holder
mRecyclerViewFirebaseListeners.put(key, listener);
viewHolder.itemView.setTag(R.id.TAG_RCV_EVENT_KEY, key);
Log.d(TAG, "Added tag for position:" + position);
// do other work here
}
第3步:在回收视图时移除视图持有者的侦听器。
@Override
public void onViewRecycled(ViewHolder holder) {
super.onViewRecycled(holder);
// Get key from the view holder
String key = (String) holder.itemView.getTag(R.id.TAG_RCV_EVENT_KEY);
Log.v(TAG, "Recycling view set for key: " + key);
// Remove listener for the retrieved key and also remove it from our map
mRootRef.child("events").child(key)
.removeEventListener(mRecyclerViewFirebaseListeners.get(key));
mRecyclerViewFirebaseListeners.remove(key);
Log.v(TAG, "On View Recycled, Removed Event listener for key: " + key);
// ...
}
第4步:删除onDestroy()
@Override
public void onDestroyView() {
super.onDestroyView();
// Iterate over map and remove listeners for the key
for (Map.Entry<String, ValueEventListener> entry : mRecyclerViewFirebaseListeners.entrySet()) {
String key = entry.getKey();
ValueEventListener value = entry.getValue();
mRootRef.child("events").child(key).removeEventListener(value);
Log.v(TAG, "Removed Event listener for key: " + key);
}
}
这将从回收站视图中删除所有侦听器。
如果您有除recyclerview之外的更多值侦听器,请为其他人使用新地图,如果它与同一路径的键模式匹配,则将其合并到此地图中。
或者,您可以将完整路径而不仅仅是一个键作为Map的键。就像在例子中我们使用了&#39; key&#39;在子广告事件下作为地图的关键字,但您可以将events/<key>
作为地图的关键字,并使用onDestroy
一次性删除mRootRef.child("<your_combined_key_from_map>").removeListener(listener)
希望这有助于某人。