Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/angular/28.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android 在启动新任务之前,需要先完成等待Firebase实时数据库的上一个任务_Android_Firebase_Firebase Realtime Database_Google Tasks Api - Fatal编程技术网

Android 在启动新任务之前,需要先完成等待Firebase实时数据库的上一个任务

Android 在启动新任务之前,需要先完成等待Firebase实时数据库的上一个任务,android,firebase,firebase-realtime-database,google-tasks-api,Android,Firebase,Firebase Realtime Database,Google Tasks Api,我正在使用我的应用程序中的从Firebase数据库检索数据,该数据库通常来自不同的节点。我有一个Firebase数据库的助手类,如下所示: public class FirebaseDbHelper { public Task<DataSnapshot> getData() { TaskCompletionSource<DataSnapshot> source = new TaskCompletionSource<>();

我正在使用我的应用程序中的从Firebase数据库检索数据,该数据库通常来自不同的节点。我有一个Firebase数据库的助手类,如下所示:

public class FirebaseDbHelper {

    public Task<DataSnapshot> getData() {
        TaskCompletionSource<DataSnapshot> source = new TaskCompletionSource<>();
        DatabaseReference dbRef = FirebaseDatabase.getInstance().getReference(FIRST_NODE).child(SUB_NODE);
        dbRef.addListenerForSingleValueEvent(new ValueEventListener() {
            @Override
            public void onDataChange(DataSnapshot dataSnapshot) {
                source.setResult(dataSnapshot);
            }

            @Override
            public void onCancelled(DatabaseError databaseError) {
                source.setException(databaseError.toException());
            }
        });
        return source.getTask();
    }

}
这正如预期的那样有效。但是,我们注意到,在检索大量数据时,即使启动任务的活动已
finish()
ed,任务仍会继续并尝试完成。我认为,这可能被视为内存泄漏,因为进程仍然在运行,即使它应该已经停止/销毁

更糟糕的是,当我尝试获取不同的数据(使用不同活动中的不同任务到Firebase中的不同节点)时,我们注意到它会先等待上一个任务完成,然后再继续这个新任务

为了提供更多的上下文,我们正在开发一个类似于Telegram的聊天应用程序,用户可以拥有多个房间,我们看到的行为发生在用户进入房间时。这就是流程:

  • 用户进入房间,我请求房间详细信息的数据
  • 在获得房间详细信息后,我显示它,然后请求消息。我只检索最近的10个。在这段时间里,我只是在活动上显示一个进度条
  • 为了完成消息细节,我从Firebase上的不同节点获取数据,这是我主要使用任务的地方

  • 获取消息后,我将其传递到视图,以显示消息,然后为新消息附加一个侦听器。一切正常
  • 当用户执行以下操作时,我在开头提到的行为是显而易见的:

  • 用户带着消息进入房间,房间详细信息会立即检索,消息仍在加载
  • 用户离开房间(按下后退按钮),这会让用户返回房间列表,并输入一个不同的列表
  • 在这一点上,检索房间细节需要很长时间——我们认为这很奇怪,因为数据一开始就没有那么大

    经过几次测试后,我们得出结论,检索时间过长是由于当前任务(获取房间详细信息)仍在等待在不同活动中启动的前一个任务(获取消息)在启动前先完成

    我试图实现我的答案,试图使用
    可取消任务
    ,但我不知道如何在当前实现中使用它,我使用的是
    任务完成源
    ,您只能设置结果或异常

    我在想,如果我将任务完成源移动到Interactior类级别而不是helper,这可能会起作用——我还没有尝试过。我认为这是可能的,但是重构我已经拥有的类需要很多时间

    所以我想为什么不尝试使用活动范围的侦听器。所以我像下面这样测试它

    在我的活动中,我添加了一个
    getActivity()
    方法,可以在演示者中调用该方法:

    public class TestPresenter
            implements TestDbInteractor.Listener {
    
        private View mView;
    
        private TestDbInteractor mDbInteractor;
    
        @Override
        void bindView(View view) {
            mView = view;
    
            mDbInteractor = new TestDbInteractor(this);
        }
    
        @Override
        void requestMessages() {
            mDbInteractor.getData(mView.getActivity());
        }
    
        // Listener stuff below
    
    }
    
    并更新了我的
    getData()
    ,如下所示:

    void getData(@NonNull Activity activity) {
        mDbHelper.getData().addOnCompleteListener(activity, task -> {
            if (task.isSuccessful()) {
                mListener.onGetDataSuccess(new MyObject(task.getResult()));
            } else {
                mListener.onGetDataFailed(task.getException());
            }
        });
    }
    

    不幸的是,这似乎不起作用,退出活动仍然会等待任务完成,然后在其他活动中启动的新任务才会启动。

    如果启动对实时数据库的查询,则无论返回的任务是否附加了任何侦听器,它都会一直运行到完成。无论是手动删除最后一个侦听器,还是使用自动删除的活动范围的侦听器,都无法取消该工作。运动中的查询保持运动状态。此外,所有进出RTDB的流量都通过单个套接字进行管道传输,这意味着在一个未完成的查询之后,后续查询的结果必须等待队列中前面的所有内容首先完成。这可能是您观察的根本原因-您有一个不完整的查询,而其他查询正在等待,无论您使用任务API如何

    幸运的是,如果启用了持久性,那么第二个查询应该由第一个查询的缓存提供服务,而不需要再次往返到服务器

    如果您需要确保在破坏活动的配置更改中保留第一次查询的结果,那么您应该使用类似于Android架构组件的内容来管理该结果,这样您就可以在配置更改后停止查询的地方继续查询。如果这样做,请不要使用活动范围的侦听器


    我写了一篇由三部分组成的博客文章,内容可能也很有趣。

    嘿,你可以使用childEventListener。使用dataSnapshot.getChildrenCount()


    嘿,艾尔,很难确切知道发生了什么。根据我的猜测,您要么试图在侦听器返回其初始数据之前取消它,这是不可能的,要么试图阻止child*回调在数据的中途触发,这是不可能的。但正如所说:如果没有一个简单的复制方法,很难说得更多。例如:我希望任务或firebase都能实现,这似乎不太可能是两者之间的交互,因为它们并没有真正意识到彼此。嗨,Puf。实际上,我看到了您关于取消Firebase DB侦听器的回答,并认为这可能是Tasks API本身的一种行为。我想我仍然需要做一个简单的应用程序,可以重新编程,让它更清晰,但这需要很多时间。我会尝试设置它,如果我完成了,我会在这里发布一个示例应用程序的链接。谢谢“。所有进出RTDB的流量都通过一个套接字进行管道传输…”是的。这绝对解释了我们注意到的行为。但奇怪的是,我们确实在应用程序中启用了持久性,所以房间细节仍然加载了一段时间的部分很奇怪——但我们将尝试更好地了解它。谢谢你
    void getData(@NonNull Activity activity) {
        mDbHelper.getData().addOnCompleteListener(activity, task -> {
            if (task.isSuccessful()) {
                mListener.onGetDataSuccess(new MyObject(task.getResult()));
            } else {
                mListener.onGetDataFailed(task.getException());
            }
        });
    }
    
        dbFriend=FirebaseDatabase.getInstance().getReference("Friend");
        dbFriend=dbFriend.child(mPreferences.getString("username","")).child("already");
    
        dbFriend.addChildEventListener(new ChildEventListener() {
            int already=0;
            @Override
            public void onChildAdded(@NonNull DataSnapshot dataSnapshot, @Nullable String s) {
    
                Username u=dataSnapshot.getValue(Username.class);
    
    
                already=alread+1;
                if(already >= dataSnapshot.getChildrenCount()){
    
                    //get to know when data fetching got completed
    
                }
    
            }
    
            @Override
            public void onChildChanged(@NonNull DataSnapshot dataSnapshot, @Nullable String s) {
    
            }
    
            @Override
            public void onChildRemoved(@NonNull DataSnapshot dataSnapshot) {
    
            }
    
            @Override
            public void onChildMoved(@NonNull DataSnapshot dataSnapshot, @Nullable String s) {
    
            }
    
            @Override
            public void onCancelled(@NonNull DatabaseError databaseError) {
    
            }
        });