如何确保一个firebase查找的完整处理程序在另一个壁炉查找之前完成

发布于 2025-02-06 10:05:26 字数 3464 浏览 3 评论 0原文

我有以下firebase DB节点结构:

UserInGroup
    --- GroupID
      --- UserId : true/false  


Users
    --- UserId
      --- Username : String
      --- ...


GroupStatus
    --- GroupId
      --- UserId: true/false    

我需要拉动第一个节点以获取组中的所有用户

,然后使用该信息获取用户帐户信息详细信息,

最终检查以查看组中的用户

状态在Java/Android中实现完成的方法?我已经为iOS提供了完整的手机。

谁能帮助我在Java中实施解决方案?

----更新----

我已经完成了以下操作:

// Create an interface to init all the callback functions
private interface AllUsersCallback {

    void onSuccess(DataSnapshot dataSnapshot);

    void onStart();

    void onFailure();

}

private void readData(Query query, AllUsersActivity.AllUsersCallback listener) {

    listener.onStart();

    query.addListenerForSingleValueEvent(new ValueEventListener() {

        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {

            if (dataSnapshot.exists()) {

                listener.onSuccess(dataSnapshot);

            } else { // dataSnapshot doesn't exist

            }

        }

        @Override
        public void onCancelled(DatabaseError databaseError) {

            Log.d(TAG, databaseError.getMessage());
            //
            listener.onFailure();

        }

    });

}

最后是活动视图:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // Init ArrayList
    userList = new ArrayList<>();

    userInGroupReference = mFirebaseDatabase.getReference("GroupUsers");

    userInGroupQuery = userInGroupReference.child(groupID).orderByValue().equalTo(true);

    // Completion Handler for Lookups
    readData(userInGroupQuery, new AllUsersActivity.AllUsersCallback() {

        @Override
        public void onSuccess(DataSnapshot dataSnapshot) {

            // Clear the List (remove dupes)
            userList.clear();

            for (DataSnapshot snapshot : dataSnapshot.getChildren()) {

                String userId = snapshot.getKey();
               
                // Call function to set usernames to the users
                setUsername(userId); 

            }

            /*
              THIS ALWAYS COMES OUT BLANK!? <--------
            */
            for (int i = 0; i < userList.size(); i++) {

                Log.e(TAG,"List element: " + userList.get(i).getUsername());

            }

        }

        @Override
        public void onStart() {

            // When starting
            Log.d("ONSTART", "Started");

        }

        @Override
        public void onFailure() {

            // If failed
            Log.d("onFailure", "Failed");

        }

    });

}

以及用于将用户用户名设置为用户列表的功能:

public void setUsername(String userId) {

    userReference = mFirebaseDatabase.getReference("Users");

    userQuery = userReference.child(userId).child("username");

    // Add handle for listener
    userQuery.addListenerForSingleValueEvent(new ValueEventListener() {

        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {

            if (dataSnapshot.exists()) {

                String username = dataSnapshot.getValue().toString();

                AllUsers result = new AllUsers(username);
                
                userList.add(result);

            }

        }

        @Override
        public void onCancelled(DatabaseError databaseError) {

        }

    });

}

I have the following Firebase DB node structure:

UserInGroup
    --- GroupID
      --- UserId : true/false  


Users
    --- UserId
      --- Username : String
      --- ...


GroupStatus
    --- GroupId
      --- UserId: true/false    

I need to pull for the first node to get all the users in the Group

Then use that info to get the users account info details

Finally check to see the users status in the Group

I cannot figure a way to implement the completionhandler in Java/Android ? I have done so for iOS with completionhandlers.

Can anyone assist with helping me implement the solution in Java?

---- UPDATE ----

I have done the following:

// Create an interface to init all the callback functions
private interface AllUsersCallback {

    void onSuccess(DataSnapshot dataSnapshot);

    void onStart();

    void onFailure();

}

private void readData(Query query, AllUsersActivity.AllUsersCallback listener) {

    listener.onStart();

    query.addListenerForSingleValueEvent(new ValueEventListener() {

        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {

            if (dataSnapshot.exists()) {

                listener.onSuccess(dataSnapshot);

            } else { // dataSnapshot doesn't exist

            }

        }

        @Override
        public void onCancelled(DatabaseError databaseError) {

            Log.d(TAG, databaseError.getMessage());
            //
            listener.onFailure();

        }

    });

}

And lastly the Activity view:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // Init ArrayList
    userList = new ArrayList<>();

    userInGroupReference = mFirebaseDatabase.getReference("GroupUsers");

    userInGroupQuery = userInGroupReference.child(groupID).orderByValue().equalTo(true);

    // Completion Handler for Lookups
    readData(userInGroupQuery, new AllUsersActivity.AllUsersCallback() {

        @Override
        public void onSuccess(DataSnapshot dataSnapshot) {

            // Clear the List (remove dupes)
            userList.clear();

            for (DataSnapshot snapshot : dataSnapshot.getChildren()) {

                String userId = snapshot.getKey();
               
                // Call function to set usernames to the users
                setUsername(userId); 

            }

            /*
              THIS ALWAYS COMES OUT BLANK!? <--------
            */
            for (int i = 0; i < userList.size(); i++) {

                Log.e(TAG,"List element: " + userList.get(i).getUsername());

            }

        }

        @Override
        public void onStart() {

            // When starting
            Log.d("ONSTART", "Started");

        }

        @Override
        public void onFailure() {

            // If failed
            Log.d("onFailure", "Failed");

        }

    });

}

and the function used to set the users username to the userList:

public void setUsername(String userId) {

    userReference = mFirebaseDatabase.getReference("Users");

    userQuery = userReference.child(userId).child("username");

    // Add handle for listener
    userQuery.addListenerForSingleValueEvent(new ValueEventListener() {

        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {

            if (dataSnapshot.exists()) {

                String username = dataSnapshot.getValue().toString();

                AllUsers result = new AllUsers(username);
                
                userList.add(result);

            }

        }

        @Override
        public void onCancelled(DatabaseError databaseError) {

        }

    });

}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

红衣飘飘貌似仙 2025-02-13 10:05:26

这些数据库调用是异步 - 回调代码不会立即运行,将来可以在您实际获取数据时运行一段时间。

链条多个依赖性异步查询的最简单方法是将每个查询放入其自身的函数中,并将其从因查询的回调中调用。在您的情况下,您可能会一次运行多个回调,因此,在每个回调完成时,您可以检查要完成的检查,并通过将列表的大小与启动的查询数进行比较来检查所有这些回调。

例如:

private ArrayList<String> userList = new ArrayList<>();
private int numUsers = 0;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    
    // other setup stuff
    startInitialQuery();
}

private void startInitialQuery() {
    // make your initial query
    
    query.addListenerForSingleValueEvent(new ValueEventListener() {

        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            if (dataSnapshot.exists()) {
                userList.clear();
                numUsers = 0; // dataSnapshot.getChildren().size();
                
                // If the size() call above works, use that, otherwise
                // you can count the number of children this way.
                for(DataSnapshot snap : dataSnapshot.getChildren()) {
                    ++numUsers;
                }   
                
                for(DataSnapshot snap : dataSnapshot.getChildren()) {
                    String userId = snap.getKey();
                    readUser(userId);
                }
            }
        }

        @Override
        public void onCancelled(DatabaseError databaseError) {
            Log.d(TAG, databaseError.getMessage());
        }
    });
}

private void readUser(String userId) {

    // make userQuery using "userId" input
    
    userQuery.addListenerForSingleValueEvent(new ValueEventListener() {

        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            if (dataSnapshot.exists()) {
                String username = dataSnapshot.getValue().toString();
                userList.add(username);
                checkLoaded();
            }
            else {
                --numUsers;
                checkLoaded();
            }
        }

        @Override
        public void onCancelled(DatabaseError databaseError) {
            Log.d(TAG, databaseError.getMessage());
            --numUsers;
            checkLoaded();
        }
    });
}

private void checkLoaded() {
    if( userList.size() == numUsers ) {
        // All done getting users! Show a toast, update a view, etc...
    }
}

或者,如果您切换到使用Kotlin和Coroutines,则可以将其写成非常简单的线性暂停功能您实际上可以使不同的任务等待。

更清洁但更具侵入性的变化将是将所有这些都移至包含每个步骤中的Livedata的ViewModel。当收到数据时,您将其发布到Livedata,UI可以观察并做出相应的反应(例如,更新视图,触发下一个呼叫等)。

Update

这是一个示例,展示了如何使用ViewModel和Livedata进行此操作


public class MainViewModel extends ViewModel {
    private final MutableLiveData<List<String>> users = new MutableLiveData<>();
    LiveData<List<String>> getUsers() {
        return users;
    }

    private final ArrayList<String> userList = new ArrayList<>();

    void startFetchingData() {
        // build query
        query.addListenerForSingleValueEvent(new ValueEventListener() {

            @Override
            public void onDataChange(DataSnapshot dataSnapshot) {
                if (dataSnapshot.exists()) {
                    userList.clear();

                    for(DataSnapshot snap : dataSnapshot.getChildren()) {
                        String userId = snap.getKey();
                        readUser(userId);
                    }
                }
            }

            @Override
            public void onCancelled(DatabaseError databaseError) {
                Log.d(TAG, databaseError.getMessage());
            }
        });
    }


    private void readUser(String userId) {
        // build userQuery
        userQuery.addListenerForSingleValueEvent(new ValueEventListener() {

            @Override
            public void onDataChange(DataSnapshot dataSnapshot) {
                if (dataSnapshot.exists()) {
                    String username = dataSnapshot.getValue().toString();
                    userList.add(username);
                    users.postValue(userList);
                }
            }

            @Override
            public void onCancelled(DatabaseError databaseError) {
                Log.d(TAG, databaseError.getMessage());
            }
        });
    }
}

,并且在活动中,您为Livedata设置了一个观察者,该观察者随时在数据更改时通知。

model = new ViewModelProvider(this).get(MainViewModel.class);

final Observer<List<String>> userObserver = userList -> {
    // Update the UI, or call something else
    // this will get called every time the list of users is
    // updated in the ViewModel
    System.out.println("TEST: got data " + userList);
};

// Observe the LiveData, passing in this activity as the LifecycleOwner and the observer.
model.getUsers().observe(this, userObserver);

model.startFetchingData();

These database calls are asynchronous - the callback code does not run immediately, it runs some time in the future when you actually get the data.

The easiest way to chain multiple dependent async queries is to put each query into its own function, and call it from the dependent query's callback. In your case, you could have multiple callbacks running at once, so as each one completes you can check for it to be done and check for them all to be done by comparing the size of the list with the number of queries launched.

For example:

private ArrayList<String> userList = new ArrayList<>();
private int numUsers = 0;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    
    // other setup stuff
    startInitialQuery();
}

private void startInitialQuery() {
    // make your initial query
    
    query.addListenerForSingleValueEvent(new ValueEventListener() {

        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            if (dataSnapshot.exists()) {
                userList.clear();
                numUsers = 0; // dataSnapshot.getChildren().size();
                
                // If the size() call above works, use that, otherwise
                // you can count the number of children this way.
                for(DataSnapshot snap : dataSnapshot.getChildren()) {
                    ++numUsers;
                }   
                
                for(DataSnapshot snap : dataSnapshot.getChildren()) {
                    String userId = snap.getKey();
                    readUser(userId);
                }
            }
        }

        @Override
        public void onCancelled(DatabaseError databaseError) {
            Log.d(TAG, databaseError.getMessage());
        }
    });
}

private void readUser(String userId) {

    // make userQuery using "userId" input
    
    userQuery.addListenerForSingleValueEvent(new ValueEventListener() {

        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            if (dataSnapshot.exists()) {
                String username = dataSnapshot.getValue().toString();
                userList.add(username);
                checkLoaded();
            }
            else {
                --numUsers;
                checkLoaded();
            }
        }

        @Override
        public void onCancelled(DatabaseError databaseError) {
            Log.d(TAG, databaseError.getMessage());
            --numUsers;
            checkLoaded();
        }
    });
}

private void checkLoaded() {
    if( userList.size() == numUsers ) {
        // All done getting users! Show a toast, update a view, etc...
    }
}

Alternately, if you switch to using Kotlin and coroutines you can write this as a pretty simple linear suspend function where you can actually make the different tasks wait.

A cleaner, but more invasive change, would be to move this all to a ViewModel that contains LiveData of each of these steps. As data is received, you post it to the LiveData and the UI can observe that and react accordingly (e.g update views, trigger the next call, etc).

Update

Here is an example showing how to do this with a ViewModel and LiveData


public class MainViewModel extends ViewModel {
    private final MutableLiveData<List<String>> users = new MutableLiveData<>();
    LiveData<List<String>> getUsers() {
        return users;
    }

    private final ArrayList<String> userList = new ArrayList<>();

    void startFetchingData() {
        // build query
        query.addListenerForSingleValueEvent(new ValueEventListener() {

            @Override
            public void onDataChange(DataSnapshot dataSnapshot) {
                if (dataSnapshot.exists()) {
                    userList.clear();

                    for(DataSnapshot snap : dataSnapshot.getChildren()) {
                        String userId = snap.getKey();
                        readUser(userId);
                    }
                }
            }

            @Override
            public void onCancelled(DatabaseError databaseError) {
                Log.d(TAG, databaseError.getMessage());
            }
        });
    }


    private void readUser(String userId) {
        // build userQuery
        userQuery.addListenerForSingleValueEvent(new ValueEventListener() {

            @Override
            public void onDataChange(DataSnapshot dataSnapshot) {
                if (dataSnapshot.exists()) {
                    String username = dataSnapshot.getValue().toString();
                    userList.add(username);
                    users.postValue(userList);
                }
            }

            @Override
            public void onCancelled(DatabaseError databaseError) {
                Log.d(TAG, databaseError.getMessage());
            }
        });
    }
}

and in the activity you set an observer for the LiveData that is notified any time the data changes.

model = new ViewModelProvider(this).get(MainViewModel.class);

final Observer<List<String>> userObserver = userList -> {
    // Update the UI, or call something else
    // this will get called every time the list of users is
    // updated in the ViewModel
    System.out.println("TEST: got data " + userList);
};

// Observe the LiveData, passing in this activity as the LifecycleOwner and the observer.
model.getUsers().observe(this, userObserver);

model.startFetchingData();
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文