【问题标题】:Performing Callbacks one after another一个接一个地执行回调
【发布时间】:2020-11-27 06:09:05
【问题描述】:

我是在 Android Java 中进行异步编程的新手。我想知道是否有办法在初始回调函数完成后运行另一个回调。现在,我认为它们是并行运行的,尽管第二个依赖于第一个。

第一次回调:

// GETTING USER
    private interface FirestoreUserCallback {
        void onCallback (User myUser);
    }

    private void getUser(final FirestoreUserCallback firestoreCallback) {
        Task<DocumentSnapshot> task = fStore.collection("users").document(fAuth.getCurrentUser().getUid()).get();
        task.addOnSuccessListener(new OnSuccessListener<DocumentSnapshot>() {
            @Override
            public void onSuccess(DocumentSnapshot documentSnapshot) {
                user = documentSnapshot.toObject(User.class);
                firestoreCallback.onCallback(user);
                Log.d(TAG, "user created");
            }
        });
        task.addOnFailureListener(new OnFailureListener() {
            @Override
            public void onFailure(@NonNull Exception e) {
                Log.d(TAG, "user creation failed");
            }
        });
    }

第二次回调:

// GETTING ALL DOCUMENTS
    private interface FirestoreDocumentCallback {
        void onCallback (List<TableEntries> myEntries);
    }

    private void getDocuments (final FirestoreDocumentCallback firestoreDocumentCallback) {
        fStore.collection("result")
                .document(Integer.toString(user.getCompanyNumber())) // need to use User object returned from the first Callback
                .collection("SAM").get()
                .addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
                    @Override
                    public void onComplete(@NonNull Task<QuerySnapshot> task) {
                        List<TableEntries> results = new ArrayList<>();
                        if (task.isSuccessful()) {
                            for (QueryDocumentSnapshot document : task.getResult()) {
                                // add objects to results ArrayList ...
                                Log.d(TAG, document.getId() + " => " + document.getData());
                            }
                            firestoreDocumentCallback.onCallback(results);
                        } else {
                            Log.d(TAG, "Error getting documents: ", task.getException());
                        }
                    }
                });
    }

创建:

getUser(new FirestoreUserCallback () {
    @Override
    public void onCallback(User myUser) {
        user = myUser;
    }
});

getDocuments(new FirestoreDocumentCallback() {
    @Override
    public void onCallback(List<TableEntries> myEntries) {
        entries = myEntries;
    }
});

getDocuments() 依赖于从第一个回调中获得其值的用户变量。我收到此错误:

java.lang.NullPointerException: Attempt to invoke virtual method 'double java.lang.Double.doubleValue()' on a null object reference

【问题讨论】:

  • 当您链接回调时,首先要记住的是您将遇到“回调地狱”的情况。那是题外话,但对您的问题的回答是,如果您依赖于完成第一个操作来开始第二个操作,那么您应该在第一个操作的回调中编写第二个操作。
  • 在您的情况下,您应该从 getUsers 的覆盖方法 onCallback 调用 getDocuments 方法,在该方法中您从回调接收用户对象。
  • 感谢您的回答!本质上,我应该将getDocuments() 移动到user = myUser 下方?
  • 是的,这将解决您的问题,检查一下

标签: java android firebase asynchronous google-cloud-firestore


【解决方案1】:

回调看起来不错。您只需要在访问它之前检查您的值是否为空。只需添加一个空检查

 if(doubleValue!=null)

【讨论】:

    【解决方案2】:

    使用 RxJava。首先,我们获取用户,然后获取文档。 Rx-Java 有一个操作符平面图。 flatmap 用于执行顺序任务,其中第二个任务依赖于第一个任务的数据。

        final CompositeDisposable disposable = new CompositeDisposable();
    //function to fetch user data
    Single<User> getUser(){
        return API.getUserData(...);
    }
    //function to fetch ducuments
    Sinlge<UserDetail> getDocuments(int userId){
        return API.getUserDetail(userId, ...);
    }
    //Subscribe
    disposable.add(getUser()
        .flatmap(user-> return getDocuments(...))
        .subscribeOn(Scheduler.io())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribeWith(new DisposableSingleObservable(){
                  @Override
                  public void onSuccess(UserDetail userDetail){
                      Log.v("Api result", "Successful";
                      //Do some work 
                  }
                  @Override
                  public void onError(Throwable e)
                      Log.v("Api result", "Error Returned");
                  }
         }));
    

    如果任一 API 调用失败,则调用 onError()。如果第一个 API 失败,则不会执行第二个 API 调用并调用 onError()。

    【讨论】:

      【解决方案3】:

      您的用例最简单的解决方案是将两个查询都传递给Tasks.whenAllSuccess() 方法,正如我在以下帖子中的回答中所解释的那样:

      因此,一旦任务完成,您就可以使用两个查询中的元素。另一种解决方案可能是按照 Android 团队的建议,将 Android Jetpack 与 LiveDataViewModel 一起使用。

      【讨论】:

        猜你喜欢
        • 2021-08-08
        • 2013-10-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-02-11
        • 1970-01-01
        • 2012-05-10
        • 2020-09-06
        相关资源
        最近更新 更多