0

I have a problem when I want to get value from Firebase database and return value from the method.

I know it's asynchronous and onDataChange is executed after "return" value from a method, I found many topics with this problem but I can't find what I must do to return it.

It's my simple method:

private int getScore(String word) {
    Log.e("DTAG", "order 1");
    String userId = getFirebaseUserId();
    DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference().child("Words").child(word).child(userId).child("score");

    rootRef.addListenerForSingleValueEvent(
            new ValueEventListener() {
                @Override
                public void onDataChange(DataSnapshot dataSnapshot) {
                  oldScore = Integer.parseInt(dataSnapshot.getValue().toString());
                    Log.e("DTAG", "order 3");
                }

                @Override
                public void onCancelled(DatabaseError databaseError) {}
            });
    Log.e("DTAG", "order 2");
return oldScore;
}
Ram Koti
  • 2,203
  • 7
  • 26
  • 36
Kakiri
  • 13
  • 2
  • Why is it absolutely required to return it from the method? It sounds like you're already aware that it shouldn't be done, and why Firebase APIs are designed the way they are. https://medium.com/google-developers/why-are-the-firebase-apis-asynchronous-e037a6654a93 – Doug Stevenson Feb 19 '18 at 21:33
  • 1
    Possible duplicate of [How to return dataSnapshot value as a result of a method?](https://stackoverflow.com/questions/47847694/how-to-return-datasnapshot-value-as-a-result-of-a-method) – Alex Mamo Feb 20 '18 at 07:58

2 Answers2

1

Since you know its asynchronous, that means you don't know when it will be completed.

A few ways to solve it would be:

  1. Callbacks (The simplest as no need for library)
  2. Event Bus
  3. Observable

First option callbacks:

You can create your own callback eg:

interface OnCompletion {

    onComplete(object: Object)

    onFailure(message: String)

}

Then you use that callback in your method:

private void getFromDb(String word, completion: onCompletion){
    Log.e("DTAG", "order 1");
    String userId = getFirebaseUserId();
    DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference().child("Words").child(word).child(userId).child("score");

    rootRef.addListenerForSingleValueEvent(
            new ValueEventListener() {
                @Override
                public void onDataChange(DataSnapshot dataSnapshot) {

                 completion.onComplete('Pass something');

                }

                @Override
                public void onCancelled(DatabaseError databaseError) {
                     completion.onFailure('Pass something');
                }
            });
}

Then you call it like:

        getFromDb("test", new OnCompletion() {
        onComplete(object: Object) {
           //Cast it and access the data here
        }

        onFailure(message: String) {
          //access the data here
        }

} ){

ian1095
  • 551
  • 4
  • 8
0

try this.

 private void getFromDb(String word){
    Log.e("DTAG", "order 1");
    String userId = getFirebaseUserId();
    DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference().child("Words").child(word).child(userId).child("score");

    rootRef.addListenerForSingleValueEvent(
            new ValueEventListener() {
                @Override
                public void onDataChange(DataSnapshot dataSnapshot) {
                  getScore(Integer.parseInt(dataSnapshot.getValue().toString()));
                }

                @Override
                public void onCancelled(DatabaseError databaseError) {

                }
            });
}

private int getScore(int score){
    Log.v("score",String.valueOf(score);
    return score
}