为Firebase EventListener提供上下文

kir*_*403 3 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) {

            }
        });
Run Code Online (Sandbox Code Playgroud)

我还需要在RecyclerView中提供太多的值监听器.滚动后,它还会导致多个值更改的事件调用.因为它绑定了现有位置的新谎言,并且没有从onViewRecycled方法中删除的引用.因此,它们被多次调用并在屏幕上随机更改数据.

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

kir*_*403 5

由于目前无法为侦听器提供上下文,因此需要跟踪所有连接的侦听器并将其删除,如David在答案中所示:https://stackoverflow.com/a/33782474/1820644


为了管理内部的价值听众,RecyclerView我提出了一个运作良好的解决方案.我正在使用FirebaseUI的RecyclerView,但解决方案应该适用于每一个RecyclerView.

第1步:首先Map<String,ValueEventListener>在您的活动中创建一个全局:

HashMap<String, ValueEventListener> mRecyclerViewFirebaseListeners = new HashMap<>();
Run Code Online (Sandbox Code Playgroud)

第2步:绑定ValueEventListenerpopulateViewHolder(在firebaseUI)或onBindViewHodler并将其添加到我们的地图mRecyclerViewFirebaseListeners.另外,Tag使用我们的的值附加a 到视图持有者

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

}
Run Code Online (Sandbox Code Playgroud)

步骤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);

    // ...

}
Run Code Online (Sandbox Code Playgroud)

第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);
    }
}
Run Code Online (Sandbox Code Playgroud)

这将从回收站视图中删除所有侦听器.

如果除了recyclerview之外还有更多的值侦听器,请为其他人使用新映射,如果它与同一路径的键模式匹配,则将其合并到此映射中.

或者,您可以将完整路径而不仅仅是一个键作为Map的键.像例如,在我们使用以下儿童"关键"的价值事件作为地图的关键,但你可以把events/<key>一个地图的钥匙,和一个删除去onDestroymRootRef.child("<your_combined_key_from_map>").removeListener(listener).

希望这有助于某人.