Knowing when Firebase has completed API call?

2019-04-21 00:44发布

I am having some trouble knowing when my Firebase API call is finished. After reading the Firebase documentation I have found the following:

Value events are always triggered last and are guaranteed to contain updates from any other events which occurred before that snapshot was taken.

I understand this to mean that only after all the onChildAdded call is finished, then the ValueEventListener is called. As a result, I thought that I can populate my RecyclerView in the onChildAdded function and then the onSingleValueListener call, I can simply finish animating my loading screen (which has started animating before this function call) and proceed. However, I have run into an issue where I put some careful System.out.println statements and found that in my case, Test 1 is called before Test 2 is ever called. This causes problems because this is actually the opposite behavior of what I wanted: I wanted the onChildAdded function to finish and then call the onSingleValueListener function that prints out Test 1 to be called. Is there any reason why this is happening? Any way around this? I would appreciate an explanation on why this is happening. Thanks!

public void getComments(final String postId, final Activity activity, final View fragmentView, final View progressOverlay) {
    final Firebase commentsRef = firebaseRef.child("/comments");
    Firebase linkRef = firebaseRef.child("/posts/" + postId);
    linkRef.addListenerForSingleValueEvent(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            System.out.println("Test 1");
            if (progressOverlay.getVisibility() == View.VISIBLE) {
                progressOverlay.setVisibility(View.GONE);
                AndroidUtils.animateView(progressOverlay, View.GONE, 0, 200);
                fragmentView.findViewById(R.id.rv_view_comments).setVisibility(View.VISIBLE);
            }
        }

        @Override
        public void onCancelled(FirebaseError firebaseError) {

        }
    });
    linkRef.addChildEventListener(new ChildEventListener() {
        @Override
        public void onChildAdded(DataSnapshot dataSnapshot, String s) {
            commentsRef.child(dataSnapshot.getKey()).addListenerForSingleValueEvent(new ValueEventListener() {
                @Override
                public void onDataChange(DataSnapshot dataSnapshot) {
                    Comment comment = dataSnapshot.getValue(Comment.class);
                    System.out.println("Test 2");
                    application.getCommentsRecyclerViewAdapter().getCommentsList().add(comment);
                    application.getCommentsRecyclerViewAdapter().notifyDataSetChanged();
                }

                @Override
                public void onCancelled(FirebaseError firebaseError) {

                }
            });
        }

        @Override
        public void onChildChanged(DataSnapshot dataSnapshot, String s) {

        }

        @Override
        public void onChildRemoved(DataSnapshot dataSnapshot) {

        }

        @Override
        public void onChildMoved(DataSnapshot dataSnapshot, String s) {

        }

        @Override
        public void onCancelled(FirebaseError firebaseError) {

        }
    });
} 

2条回答
混吃等死
2楼-- · 2019-04-21 01:16

With this code "Firebase linkRef = firebaseRef.child("/posts/" + postId);" I could see that you're using legacy Firebase API. Its deprecated now!

Kindly update your code to new Firebase 3.x.x API.

Below two are independent async call; Based on your use-case, you can use either one of the listener to read your data.

1. linkRef.addListenerForSingleValueEvent(new ValueEventListener() {});
2. linkRef.addChildEventListener(new ChildEventListener() {});

You can refer the firebase document to get more information about database listeners. https://firebase.google.com/docs/database/android/retrieve-data

With the following code snippet, you can retrieve and populate your list of comments.

public void getComments(final String postId, final Activity activity, final View fragmentView, final View progressOverlay) {
    DatabaseReference commentsRef = firebaseRef.child("/comments");
    DatabaseReference linkRef = commentsRef.child("/posts/" + postId);
    linkRef.addListenerForSingleValueEvent(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            // Iterate through data-snapshot, and update your Adapter dataset
            for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
                Comment comment = snapshot.getValue(Comment.class);
                application.getCommentsRecyclerViewAdapter().getCommentsList().add(comment);
            }
            application.getCommentsRecyclerViewAdapter().notifyDataSetChanged();

            // Dismiss your loading progressbar
            if (progressOverlay.getVisibility() == View.VISIBLE) {
                progressOverlay.setVisibility(View.GONE);
                AndroidUtils.animateView(progressOverlay, View.GONE, 0, 200);
                fragmentView.findViewById(R.id.rv_view_comments).setVisibility(View.VISIBLE);
            }
        }

        @Override
        public void onCancelled(DatabaseError databaseError) {
            // Handle fail case here
        }
    });

Hope this would help you!

查看更多
我欲成王,谁敢阻挡
3楼-- · 2019-04-21 01:40

You may want to use the **FirebaseRecyclerAdapter** class that the Firebase team makes available in FirebaseUI-Android (see https://github.com/firebase/FirebaseUI-Android/blob/master/database/src/main/java/com/firebase/ui/database/FirebaseRecyclerAdapter.java)

In your gradle file add the line below (check here for latest version number in the readme) compile 'com.firebaseui:firebase-ui-database:0.4.3'

查看更多
登录 后发表回答