为Firebase EventListener提供上下文

时间:2016-07-12 09:01:37

标签: android firebase firebase-realtime-database

我在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方法中删除的引用。因此,它们被多次调用并在屏幕上随机更改数据。

使用上下文可以更轻松地设置值事件侦听器。有没有办法跟踪所有听众?也没有方法可以让听众参考。

1 个答案:

答案 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)

希望这有助于某人。