我真的应该删除 ValueEventListener 吗?

Posted

技术标签:

【中文标题】我真的应该删除 ValueEventListener 吗?【英文标题】:Should I actually remove the ValueEventListener? 【发布时间】:2018-07-29 09:41:33 【问题描述】:
        DatabaseReference Ref = FirebaseDatabase.getInstance().getReference(Constants.Client + "/" + path);
        Ref.keepSynced(true);
        Ref.addValueEventListener(new ValueEventListener() 
            @Override
            public void onDataChange(DataSnapshot dataSnapshot) 

            

            @Override
            public void onCancelled(DatabaseError databaseError) 

            
        );

我知道ValueEventListener 在一个新线程中运行,我是否应该在任何时候删除它以进行正确的线程管理? (例如并行运行的线程不多)。如果是,怎么做?

【问题讨论】:

是的。您应该在组件生命周期中将其删除。否则它将在不知道组件状态的情况下为您提供回调(称为 Activity)。移除onStop()onDestroy()中的监听器。 我已经尝试删除它,我已经尝试了所有堆栈溢出的答案,但我无法删除它。有人可以帮忙吗? 【参考方案1】:

在谈论监听器时,是的,您需要根据活动的生命周期删除它们,为此您需要使用以下代码行:

databaseReference.removeEventListener(valueEventListener);

请记住,如果您不这样做,您最终会浪费电池和带宽。所以:

    如果您在onStart 中添加了侦听器,则必须在onStop 中删除它。 如果您在onResume 中添加了侦听器,则必须在onPause 中删除它。 如果您在onCreate 中添加了侦听器,则必须在onDestroy 中删除它。

但请记住,onDestroy 总是被 not 调用,所以最后一个选项并不总是一个好的选择。

还有另一种不需要删除监听器的方法,那就是使用addListenerForSingleValueEvent:

为此位置的数据中的单个更改添加侦听器。

【讨论】:

为什么不总是调用 onDestroy? 请查看here和here,以便更好地理解。 使用 addListenerForSingleValueEvent() 时,您仍应将其从 DatabaseReference 中删除。如果它永远不会触发(设备离线),则永远不会自动删除侦听器,并可能导致内存泄漏。 @javmarina 使用addListenerForSingleValueEvent() 时,没有应删除的侦听器,因为侦听器只触发一次。 我检查了addListenerForSingleValueEvent() 的源代码,它基本上添加了一个新的侦听器,当onDataChange() 被调用时它会被删除。如果两个回调方法都没有被触发,例如当设备离线时,监听器不会被移除。尽管这种情况很少见,但我们应该在代码中处理它。请参阅我对我提出的解决方案的回答。【参考方案2】:

要删除 ValueEventListener,您可以这样做:

移除监听者的匿名性。

从这里更改代码:-

      Ref.addValueEventListener(new ValueEventListener() 
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) 

        

        @Override
        public void onCancelled(DatabaseError databaseError) 

        
    );

进入这个:

   ValueEventListener listener= new ValueEventListener() 
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) 

        

        @Override
        public void onCancelled(DatabaseError databaseError) 

        
    );
Ref.addValueEventListener(listener);

现在您可以移除监听器了:

   @Override
public void onDestroy() 
if (Ref != null && listener != null) 
   Ref.removeEventListener(listener);
    
 

您需要删除它,这样监听器就不会在其他活动生命周期中保持运行,例如 onDestroy()

【讨论】:

【参考方案3】:

我遇到了同样的问题,导致大量内存泄漏。所以我创建了一个新类来处理添加的侦听器,并在调用相应的方法(onPause()、onStop() 或 onDestroy())时将其删除。使用androidx.lifecycle 库,适用于活动和片段(实际上,任何实现LifecycleOwner 的类)。

您可以查看代码here。如果不手动添加 androidx.lifecycle 依赖项,您可能会很好,但您也可以将其添加到模块级 build.gradle:

implementation 'androidx.lifecycle:lifecycle-runtime:VERSION'

在您当前的代码中,而不是:

databaseReference.addValueEventListener(valueEventListener);
// or
databaseReference.addListenerForSingleValueEvent(valueEventListener);

你需要使用:

addValueEventListener(databaseReference, valueEventListener); 
// or
addListenerForSingleValueEvent(databaseReference, valueEventListener);

这在从使用 FirebaseListenerHandler 的活动或片段中调用时有效,如 gist 所示。如果您需要在其他情况下(如服务)添加 Firebase 侦听器,您仍然需要手动删除它们。

【讨论】:

以上是关于我真的应该删除 ValueEventListener 吗?的主要内容,如果未能解决你的问题,请参考以下文章

我不小心的手机里的TTS文件删除了?我应该怎么样重新下载一个

孤儿删除不起作用

显式删除临时表或让SQL Server处理它

开挂了!这5个Word技巧真的是超级实用,值得收藏!

Grails 更新而不是删除

pm2到底是啥呢?你真的了解吗