How to return dataSnapshot value as a result of a method?












13














I don't have much experience with Java. I'm not sure if this question is stupid, but I need to get a user name from Firebase Realtime Database and return this name as a result of this method. So... I figured out how to get this value, but I don't understand how to return it as result of this method. What's the best way to do this?



private String getUserName(String uid) {
databaseReference.child(String.format("users/%s/name", uid))
.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
// How to return this value?
dataSnapshot.getValue(String.class);
}

@Override
public void onCancelled(DatabaseError databaseError) {}
});
}









share|improve this question


















  • 1




    Like @PeterHaddad mentioned, the onDataChange method is asynchronous, which means that it will always return null. May I ask: Why do you need to return the user name? Why not simply use this name inside onDataChange?
    – Rosário Pereira Fernandes
    Dec 16 '17 at 23:28






  • 2




    As @PeterHaddad said, because onDataChange() method is called asynchronous, it won't work. Please see my answer.
    – Alex Mamo
    Dec 17 '17 at 9:37






  • 1




    Read this to understand why Firebase APIs are async: medium.com/@CodingDoug/…
    – Doug Stevenson
    Feb 16 at 16:20










  • Read this to understand how to solve asynchronous database with one or more databasereference: stackoverflow.com/questions/48720701/…
    – Peter Haddad
    Feb 21 at 20:03
















13














I don't have much experience with Java. I'm not sure if this question is stupid, but I need to get a user name from Firebase Realtime Database and return this name as a result of this method. So... I figured out how to get this value, but I don't understand how to return it as result of this method. What's the best way to do this?



private String getUserName(String uid) {
databaseReference.child(String.format("users/%s/name", uid))
.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
// How to return this value?
dataSnapshot.getValue(String.class);
}

@Override
public void onCancelled(DatabaseError databaseError) {}
});
}









share|improve this question


















  • 1




    Like @PeterHaddad mentioned, the onDataChange method is asynchronous, which means that it will always return null. May I ask: Why do you need to return the user name? Why not simply use this name inside onDataChange?
    – Rosário Pereira Fernandes
    Dec 16 '17 at 23:28






  • 2




    As @PeterHaddad said, because onDataChange() method is called asynchronous, it won't work. Please see my answer.
    – Alex Mamo
    Dec 17 '17 at 9:37






  • 1




    Read this to understand why Firebase APIs are async: medium.com/@CodingDoug/…
    – Doug Stevenson
    Feb 16 at 16:20










  • Read this to understand how to solve asynchronous database with one or more databasereference: stackoverflow.com/questions/48720701/…
    – Peter Haddad
    Feb 21 at 20:03














13












13








13


7





I don't have much experience with Java. I'm not sure if this question is stupid, but I need to get a user name from Firebase Realtime Database and return this name as a result of this method. So... I figured out how to get this value, but I don't understand how to return it as result of this method. What's the best way to do this?



private String getUserName(String uid) {
databaseReference.child(String.format("users/%s/name", uid))
.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
// How to return this value?
dataSnapshot.getValue(String.class);
}

@Override
public void onCancelled(DatabaseError databaseError) {}
});
}









share|improve this question













I don't have much experience with Java. I'm not sure if this question is stupid, but I need to get a user name from Firebase Realtime Database and return this name as a result of this method. So... I figured out how to get this value, but I don't understand how to return it as result of this method. What's the best way to do this?



private String getUserName(String uid) {
databaseReference.child(String.format("users/%s/name", uid))
.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
// How to return this value?
dataSnapshot.getValue(String.class);
}

@Override
public void onCancelled(DatabaseError databaseError) {}
});
}






android firebase firebase-realtime-database






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Dec 16 '17 at 16:25









Ilya Cucumber

10118




10118








  • 1




    Like @PeterHaddad mentioned, the onDataChange method is asynchronous, which means that it will always return null. May I ask: Why do you need to return the user name? Why not simply use this name inside onDataChange?
    – Rosário Pereira Fernandes
    Dec 16 '17 at 23:28






  • 2




    As @PeterHaddad said, because onDataChange() method is called asynchronous, it won't work. Please see my answer.
    – Alex Mamo
    Dec 17 '17 at 9:37






  • 1




    Read this to understand why Firebase APIs are async: medium.com/@CodingDoug/…
    – Doug Stevenson
    Feb 16 at 16:20










  • Read this to understand how to solve asynchronous database with one or more databasereference: stackoverflow.com/questions/48720701/…
    – Peter Haddad
    Feb 21 at 20:03














  • 1




    Like @PeterHaddad mentioned, the onDataChange method is asynchronous, which means that it will always return null. May I ask: Why do you need to return the user name? Why not simply use this name inside onDataChange?
    – Rosário Pereira Fernandes
    Dec 16 '17 at 23:28






  • 2




    As @PeterHaddad said, because onDataChange() method is called asynchronous, it won't work. Please see my answer.
    – Alex Mamo
    Dec 17 '17 at 9:37






  • 1




    Read this to understand why Firebase APIs are async: medium.com/@CodingDoug/…
    – Doug Stevenson
    Feb 16 at 16:20










  • Read this to understand how to solve asynchronous database with one or more databasereference: stackoverflow.com/questions/48720701/…
    – Peter Haddad
    Feb 21 at 20:03








1




1




Like @PeterHaddad mentioned, the onDataChange method is asynchronous, which means that it will always return null. May I ask: Why do you need to return the user name? Why not simply use this name inside onDataChange?
– Rosário Pereira Fernandes
Dec 16 '17 at 23:28




Like @PeterHaddad mentioned, the onDataChange method is asynchronous, which means that it will always return null. May I ask: Why do you need to return the user name? Why not simply use this name inside onDataChange?
– Rosário Pereira Fernandes
Dec 16 '17 at 23:28




2




2




As @PeterHaddad said, because onDataChange() method is called asynchronous, it won't work. Please see my answer.
– Alex Mamo
Dec 17 '17 at 9:37




As @PeterHaddad said, because onDataChange() method is called asynchronous, it won't work. Please see my answer.
– Alex Mamo
Dec 17 '17 at 9:37




1




1




Read this to understand why Firebase APIs are async: medium.com/@CodingDoug/…
– Doug Stevenson
Feb 16 at 16:20




Read this to understand why Firebase APIs are async: medium.com/@CodingDoug/…
– Doug Stevenson
Feb 16 at 16:20












Read this to understand how to solve asynchronous database with one or more databasereference: stackoverflow.com/questions/48720701/…
– Peter Haddad
Feb 21 at 20:03




Read this to understand how to solve asynchronous database with one or more databasereference: stackoverflow.com/questions/48720701/…
– Peter Haddad
Feb 21 at 20:03












3 Answers
3






active

oldest

votes


















44














This is a classic issue with asynchronous web APIs. You cannot return something now that hasn't been loaded yet. With other words, you cannot simply create a global variable and use it outside onDataChange() method because it will always be null. This is happening because onDataChange() method is called asynchronous. Depending on your connection speed and the state, it may take from a few hundred milliseconds to a few seconds before that data is available.



But not only Firebase Realtime Database loads data asynchronously, almost all of modern other web APIs do, since it may take some time. So instead of waiting for the data (which can lead to unresponsive application dialogs for your users), your main application code continues while the data is loaded on a secondary thread. Then when the data is available, your onDataChange() method is called and can use the data. With other words, by the time onDataChange() method is called your data is not loaded yet.



Let's take an example, by placing a few log statements in the code, to see more clearly what's going on.



private String getUserName(String uid) {
Log.d("TAG", "Before attaching the listener!");
databaseReference.child(String.format("users/%s/name", uid)).addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
// How to return this value?
dataSnapshot.getValue(String.class);
Log.d("TAG", "Inside onDataChange() method!");
}

@Override
public void onCancelled(DatabaseError databaseError) {}
});
Log.d("TAG", "After attaching the listener!");
}


If we run this code will, the output wil be:




Before attaching the listener!



After attaching the listener!



Inside onDataChange() method!




This is probably not what you expected, but it explains precisely why your data is null when returning it.



The initial response for most developers is to try and "fix" this asynchronous behavior, which I personally recommend against this. The web is asynchronous, and the sooner you accept that, the sooner you can learn how to become productive with modern web APIs.



I've found it easiest to reframe problems for this asynchronous paradigm. Instead of saying "First get the data, then log it", I frame the problem as "Start to get data. When the data is loaded, log it". This means that any code that requires the data must be inside onDataChange() method or called from inside there, like this:



databaseReference.child(String.format("users/%s/name", uid)).addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
// How to return this value?
if(dataSnapshot != null) {
System.out.println(dataSnapshot.getValue(String.class));
}
}

@Override
public void onCancelled(DatabaseError databaseError) {}
});


If you want to use that outside, there is another approach. You need to create your own callback to wait for Firebase to return you the data. To achieve this, first you need to create an interface like this:



public interface MyCallback {
void onCallback(String value);
}


Then you need to create a method that is actually getting the data from the database. This method should look like this:



public void readData(MyCallback myCallback) {
databaseReference.child(String.format("users/%s/name", uid)).addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
String value = dataSnapshot.getValue(String.class);
myCallback.onCallback(value);
}

@Override
public void onCancelled(DatabaseError databaseError) {}
});
}


In the end just simply call readData() method and pass an instance of the MyCallback interface as an argument wherever you need it like this:



readData(new MyCallback() {
@Override
public void onCallback(String value) {
Log.d("TAG", value);
}
});


This is the only way in which you can use that value outside onDataChange() method. For more information, you can take also a look at this video.






share|improve this answer























  • Can this be achieved using Future interface and Callable? developer.android.com/reference/java/util/concurrent/Future
    – Peter Haddad
    Jul 31 at 16:46










  • Hi Peter! It might work. I didn't tried yet but I will. I don't know if you know this, but here is an interesting article.
    – Alex Mamo
    Jul 31 at 18:25












  • Yes, I saw it before since it is written as a comment in many places. But, I haven't read it, because I know how asynchronous works after reading couple of Q&A here. Anyway, I read it now and I guess it is better not to use Future since we need to use newSingleThreadExecutor() that creates another thread, and since the api is asychronous then it is already in a thread in java and we have to maintain this thread also and write more code.
    – Peter Haddad
    Jul 31 at 19:43










  • @PeterHaddad Firebase client already runs all network operations in a background thread so I think you are right. There is no need for that. Thanks for providing me that resource!
    – Alex Mamo
    Jul 31 at 20:24



















4














I believe I understand what you are asking. Although you say you want to "return" it (per se) from the fetch method, it may suffice to say you actually just want to be able to use the value retrieved after your fetch has completed. If so, this is what you need to do:




  1. Create a variable at the top of your class

  2. Retrieve your value (which you have done mostly correctly)

  3. Set the public variable in your class equal to value retrieved


Once your fetch succeeds, you could do many things with the variable. 4a and 4b are some simple examples:



4a. Edit:
As an example of use, you can trigger whatever else you need to run in your class that uses yourNameVariable (and you can be sure it yourNameVariable not null)



4b. Edit:
As an example of use, you can use the variable in a function that is triggered by a button's onClickListener.





Try this.



// 1. Create a variable at the top of your class
private String yourNameVariable;

// 2. Retrieve your value (which you have done mostly correctly)
private void getUserName(String uid) {
databaseReference.child(String.format("users/%s/name", uid))
.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
// 3. Set the public variable in your class equal to value retrieved
yourNameVariable = dataSnapshot.getValue(String.class);
// 4a. EDIT: now that your fetch succeeded, you can trigger whatever else you need to run in your class that uses `yourNameVariable`, and you can be sure `yourNameVariable` is not null.
sayHiToMe();
}

@Override
public void onCancelled(DatabaseError databaseError) {}
});
}

// (part of step 4a)
public void sayHiToMe() {
Log.d(TAG, "hi there, " + yourNameVariable);
}

// 4b. use the variable in a function triggered by the onClickListener of a button.
public void helloButtonWasPressed() {
if (yourNameVariable != null) {
Log.d(TAG, "hi there, " + yourNameVariable);
}
}


Then, you can use yourNameVariable wherever you would like throughout your class.





Note: just be sure you check that yourNameVariable is not null when using it since onDataChange is asynchronous and may not have completed at the time you attempt to use it elsewhere.






share|improve this answer



















  • 1




    This is an incorrect answer. This is not how thing are going on when it comes to asynchronous methods. Using this answer you'll have your variable yourNameVariable to be always null when using "wherever you would like throughout your class". You can use it only in your onDataChange() method. That's it.
    – Alex Mamo
    Dec 17 '17 at 9:32












  • @AlexMamo, your solution of defining an interface works nicely, but the following part of your comment is incorrect: "yourNameVariable to be always null." For those looking for a more lightweight solution (that does not require defining an interface) this works well. Once the variable has been retrieved and set, they can trigger any functions that need the result and know that the variable is not null (as long as it exists on firebase in the first place). I have updated my example so you can see a concrete use-case.
    – Rbar
    Dec 17 '17 at 19:08












  • Furthermore calling that method has nothing to do with asynchronous behaviour of methods. Calling that method is the same as using this line Log.d(TAG, "hi there, " + yourNameVariable); inside onDataChange() method. This means that when onDataChange() method is triggered you are calling that method.
    – Alex Mamo
    Dec 18 '17 at 8:00












  • @AlexMamo, the function was merely a single example. You can do many other things that do not automatically trigger a funciton. For another simple example, a button could be visible once the data has loaded and triggering the button would do something with the data you have fetched. Again, your example is nice and I am not arguing that it shouldn't be the accepted answer. That being said, your blanket statement (even the full one) of yourNameVariable will be be always null when using "wherever you would like throughout your class". is not true for all cases ... (continued)
    – Rbar
    Dec 18 '17 at 18:47












  • There are several cases in which you could use the value retrieved outside of fetching the data. My point is merely that there is more than one way to skin a cat; some lighter solutions like the one I have posted may work better for some people, and your may work better for many others. No need to get worked up, just sharing knowledge here.
    – Rbar
    Dec 18 '17 at 18:47



















2














Here's a crazy Idea, inside onDataChange, put it inside a TextView with visibility gone
textview.setVisiblity(Gone) or something, XD
then do something like



textview.setText(dataSnapshot.getValue(String.class))




then later get it with textview.getText().toString()



just a crazy simple Idea.






share|improve this answer























    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f47847694%2fhow-to-return-datasnapshot-value-as-a-result-of-a-method%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    3 Answers
    3






    active

    oldest

    votes








    3 Answers
    3






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    44














    This is a classic issue with asynchronous web APIs. You cannot return something now that hasn't been loaded yet. With other words, you cannot simply create a global variable and use it outside onDataChange() method because it will always be null. This is happening because onDataChange() method is called asynchronous. Depending on your connection speed and the state, it may take from a few hundred milliseconds to a few seconds before that data is available.



    But not only Firebase Realtime Database loads data asynchronously, almost all of modern other web APIs do, since it may take some time. So instead of waiting for the data (which can lead to unresponsive application dialogs for your users), your main application code continues while the data is loaded on a secondary thread. Then when the data is available, your onDataChange() method is called and can use the data. With other words, by the time onDataChange() method is called your data is not loaded yet.



    Let's take an example, by placing a few log statements in the code, to see more clearly what's going on.



    private String getUserName(String uid) {
    Log.d("TAG", "Before attaching the listener!");
    databaseReference.child(String.format("users/%s/name", uid)).addListenerForSingleValueEvent(new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {
    // How to return this value?
    dataSnapshot.getValue(String.class);
    Log.d("TAG", "Inside onDataChange() method!");
    }

    @Override
    public void onCancelled(DatabaseError databaseError) {}
    });
    Log.d("TAG", "After attaching the listener!");
    }


    If we run this code will, the output wil be:




    Before attaching the listener!



    After attaching the listener!



    Inside onDataChange() method!




    This is probably not what you expected, but it explains precisely why your data is null when returning it.



    The initial response for most developers is to try and "fix" this asynchronous behavior, which I personally recommend against this. The web is asynchronous, and the sooner you accept that, the sooner you can learn how to become productive with modern web APIs.



    I've found it easiest to reframe problems for this asynchronous paradigm. Instead of saying "First get the data, then log it", I frame the problem as "Start to get data. When the data is loaded, log it". This means that any code that requires the data must be inside onDataChange() method or called from inside there, like this:



    databaseReference.child(String.format("users/%s/name", uid)).addListenerForSingleValueEvent(new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {
    // How to return this value?
    if(dataSnapshot != null) {
    System.out.println(dataSnapshot.getValue(String.class));
    }
    }

    @Override
    public void onCancelled(DatabaseError databaseError) {}
    });


    If you want to use that outside, there is another approach. You need to create your own callback to wait for Firebase to return you the data. To achieve this, first you need to create an interface like this:



    public interface MyCallback {
    void onCallback(String value);
    }


    Then you need to create a method that is actually getting the data from the database. This method should look like this:



    public void readData(MyCallback myCallback) {
    databaseReference.child(String.format("users/%s/name", uid)).addListenerForSingleValueEvent(new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {
    String value = dataSnapshot.getValue(String.class);
    myCallback.onCallback(value);
    }

    @Override
    public void onCancelled(DatabaseError databaseError) {}
    });
    }


    In the end just simply call readData() method and pass an instance of the MyCallback interface as an argument wherever you need it like this:



    readData(new MyCallback() {
    @Override
    public void onCallback(String value) {
    Log.d("TAG", value);
    }
    });


    This is the only way in which you can use that value outside onDataChange() method. For more information, you can take also a look at this video.






    share|improve this answer























    • Can this be achieved using Future interface and Callable? developer.android.com/reference/java/util/concurrent/Future
      – Peter Haddad
      Jul 31 at 16:46










    • Hi Peter! It might work. I didn't tried yet but I will. I don't know if you know this, but here is an interesting article.
      – Alex Mamo
      Jul 31 at 18:25












    • Yes, I saw it before since it is written as a comment in many places. But, I haven't read it, because I know how asynchronous works after reading couple of Q&A here. Anyway, I read it now and I guess it is better not to use Future since we need to use newSingleThreadExecutor() that creates another thread, and since the api is asychronous then it is already in a thread in java and we have to maintain this thread also and write more code.
      – Peter Haddad
      Jul 31 at 19:43










    • @PeterHaddad Firebase client already runs all network operations in a background thread so I think you are right. There is no need for that. Thanks for providing me that resource!
      – Alex Mamo
      Jul 31 at 20:24
















    44














    This is a classic issue with asynchronous web APIs. You cannot return something now that hasn't been loaded yet. With other words, you cannot simply create a global variable and use it outside onDataChange() method because it will always be null. This is happening because onDataChange() method is called asynchronous. Depending on your connection speed and the state, it may take from a few hundred milliseconds to a few seconds before that data is available.



    But not only Firebase Realtime Database loads data asynchronously, almost all of modern other web APIs do, since it may take some time. So instead of waiting for the data (which can lead to unresponsive application dialogs for your users), your main application code continues while the data is loaded on a secondary thread. Then when the data is available, your onDataChange() method is called and can use the data. With other words, by the time onDataChange() method is called your data is not loaded yet.



    Let's take an example, by placing a few log statements in the code, to see more clearly what's going on.



    private String getUserName(String uid) {
    Log.d("TAG", "Before attaching the listener!");
    databaseReference.child(String.format("users/%s/name", uid)).addListenerForSingleValueEvent(new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {
    // How to return this value?
    dataSnapshot.getValue(String.class);
    Log.d("TAG", "Inside onDataChange() method!");
    }

    @Override
    public void onCancelled(DatabaseError databaseError) {}
    });
    Log.d("TAG", "After attaching the listener!");
    }


    If we run this code will, the output wil be:




    Before attaching the listener!



    After attaching the listener!



    Inside onDataChange() method!




    This is probably not what you expected, but it explains precisely why your data is null when returning it.



    The initial response for most developers is to try and "fix" this asynchronous behavior, which I personally recommend against this. The web is asynchronous, and the sooner you accept that, the sooner you can learn how to become productive with modern web APIs.



    I've found it easiest to reframe problems for this asynchronous paradigm. Instead of saying "First get the data, then log it", I frame the problem as "Start to get data. When the data is loaded, log it". This means that any code that requires the data must be inside onDataChange() method or called from inside there, like this:



    databaseReference.child(String.format("users/%s/name", uid)).addListenerForSingleValueEvent(new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {
    // How to return this value?
    if(dataSnapshot != null) {
    System.out.println(dataSnapshot.getValue(String.class));
    }
    }

    @Override
    public void onCancelled(DatabaseError databaseError) {}
    });


    If you want to use that outside, there is another approach. You need to create your own callback to wait for Firebase to return you the data. To achieve this, first you need to create an interface like this:



    public interface MyCallback {
    void onCallback(String value);
    }


    Then you need to create a method that is actually getting the data from the database. This method should look like this:



    public void readData(MyCallback myCallback) {
    databaseReference.child(String.format("users/%s/name", uid)).addListenerForSingleValueEvent(new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {
    String value = dataSnapshot.getValue(String.class);
    myCallback.onCallback(value);
    }

    @Override
    public void onCancelled(DatabaseError databaseError) {}
    });
    }


    In the end just simply call readData() method and pass an instance of the MyCallback interface as an argument wherever you need it like this:



    readData(new MyCallback() {
    @Override
    public void onCallback(String value) {
    Log.d("TAG", value);
    }
    });


    This is the only way in which you can use that value outside onDataChange() method. For more information, you can take also a look at this video.






    share|improve this answer























    • Can this be achieved using Future interface and Callable? developer.android.com/reference/java/util/concurrent/Future
      – Peter Haddad
      Jul 31 at 16:46










    • Hi Peter! It might work. I didn't tried yet but I will. I don't know if you know this, but here is an interesting article.
      – Alex Mamo
      Jul 31 at 18:25












    • Yes, I saw it before since it is written as a comment in many places. But, I haven't read it, because I know how asynchronous works after reading couple of Q&A here. Anyway, I read it now and I guess it is better not to use Future since we need to use newSingleThreadExecutor() that creates another thread, and since the api is asychronous then it is already in a thread in java and we have to maintain this thread also and write more code.
      – Peter Haddad
      Jul 31 at 19:43










    • @PeterHaddad Firebase client already runs all network operations in a background thread so I think you are right. There is no need for that. Thanks for providing me that resource!
      – Alex Mamo
      Jul 31 at 20:24














    44












    44








    44






    This is a classic issue with asynchronous web APIs. You cannot return something now that hasn't been loaded yet. With other words, you cannot simply create a global variable and use it outside onDataChange() method because it will always be null. This is happening because onDataChange() method is called asynchronous. Depending on your connection speed and the state, it may take from a few hundred milliseconds to a few seconds before that data is available.



    But not only Firebase Realtime Database loads data asynchronously, almost all of modern other web APIs do, since it may take some time. So instead of waiting for the data (which can lead to unresponsive application dialogs for your users), your main application code continues while the data is loaded on a secondary thread. Then when the data is available, your onDataChange() method is called and can use the data. With other words, by the time onDataChange() method is called your data is not loaded yet.



    Let's take an example, by placing a few log statements in the code, to see more clearly what's going on.



    private String getUserName(String uid) {
    Log.d("TAG", "Before attaching the listener!");
    databaseReference.child(String.format("users/%s/name", uid)).addListenerForSingleValueEvent(new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {
    // How to return this value?
    dataSnapshot.getValue(String.class);
    Log.d("TAG", "Inside onDataChange() method!");
    }

    @Override
    public void onCancelled(DatabaseError databaseError) {}
    });
    Log.d("TAG", "After attaching the listener!");
    }


    If we run this code will, the output wil be:




    Before attaching the listener!



    After attaching the listener!



    Inside onDataChange() method!




    This is probably not what you expected, but it explains precisely why your data is null when returning it.



    The initial response for most developers is to try and "fix" this asynchronous behavior, which I personally recommend against this. The web is asynchronous, and the sooner you accept that, the sooner you can learn how to become productive with modern web APIs.



    I've found it easiest to reframe problems for this asynchronous paradigm. Instead of saying "First get the data, then log it", I frame the problem as "Start to get data. When the data is loaded, log it". This means that any code that requires the data must be inside onDataChange() method or called from inside there, like this:



    databaseReference.child(String.format("users/%s/name", uid)).addListenerForSingleValueEvent(new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {
    // How to return this value?
    if(dataSnapshot != null) {
    System.out.println(dataSnapshot.getValue(String.class));
    }
    }

    @Override
    public void onCancelled(DatabaseError databaseError) {}
    });


    If you want to use that outside, there is another approach. You need to create your own callback to wait for Firebase to return you the data. To achieve this, first you need to create an interface like this:



    public interface MyCallback {
    void onCallback(String value);
    }


    Then you need to create a method that is actually getting the data from the database. This method should look like this:



    public void readData(MyCallback myCallback) {
    databaseReference.child(String.format("users/%s/name", uid)).addListenerForSingleValueEvent(new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {
    String value = dataSnapshot.getValue(String.class);
    myCallback.onCallback(value);
    }

    @Override
    public void onCancelled(DatabaseError databaseError) {}
    });
    }


    In the end just simply call readData() method and pass an instance of the MyCallback interface as an argument wherever you need it like this:



    readData(new MyCallback() {
    @Override
    public void onCallback(String value) {
    Log.d("TAG", value);
    }
    });


    This is the only way in which you can use that value outside onDataChange() method. For more information, you can take also a look at this video.






    share|improve this answer














    This is a classic issue with asynchronous web APIs. You cannot return something now that hasn't been loaded yet. With other words, you cannot simply create a global variable and use it outside onDataChange() method because it will always be null. This is happening because onDataChange() method is called asynchronous. Depending on your connection speed and the state, it may take from a few hundred milliseconds to a few seconds before that data is available.



    But not only Firebase Realtime Database loads data asynchronously, almost all of modern other web APIs do, since it may take some time. So instead of waiting for the data (which can lead to unresponsive application dialogs for your users), your main application code continues while the data is loaded on a secondary thread. Then when the data is available, your onDataChange() method is called and can use the data. With other words, by the time onDataChange() method is called your data is not loaded yet.



    Let's take an example, by placing a few log statements in the code, to see more clearly what's going on.



    private String getUserName(String uid) {
    Log.d("TAG", "Before attaching the listener!");
    databaseReference.child(String.format("users/%s/name", uid)).addListenerForSingleValueEvent(new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {
    // How to return this value?
    dataSnapshot.getValue(String.class);
    Log.d("TAG", "Inside onDataChange() method!");
    }

    @Override
    public void onCancelled(DatabaseError databaseError) {}
    });
    Log.d("TAG", "After attaching the listener!");
    }


    If we run this code will, the output wil be:




    Before attaching the listener!



    After attaching the listener!



    Inside onDataChange() method!




    This is probably not what you expected, but it explains precisely why your data is null when returning it.



    The initial response for most developers is to try and "fix" this asynchronous behavior, which I personally recommend against this. The web is asynchronous, and the sooner you accept that, the sooner you can learn how to become productive with modern web APIs.



    I've found it easiest to reframe problems for this asynchronous paradigm. Instead of saying "First get the data, then log it", I frame the problem as "Start to get data. When the data is loaded, log it". This means that any code that requires the data must be inside onDataChange() method or called from inside there, like this:



    databaseReference.child(String.format("users/%s/name", uid)).addListenerForSingleValueEvent(new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {
    // How to return this value?
    if(dataSnapshot != null) {
    System.out.println(dataSnapshot.getValue(String.class));
    }
    }

    @Override
    public void onCancelled(DatabaseError databaseError) {}
    });


    If you want to use that outside, there is another approach. You need to create your own callback to wait for Firebase to return you the data. To achieve this, first you need to create an interface like this:



    public interface MyCallback {
    void onCallback(String value);
    }


    Then you need to create a method that is actually getting the data from the database. This method should look like this:



    public void readData(MyCallback myCallback) {
    databaseReference.child(String.format("users/%s/name", uid)).addListenerForSingleValueEvent(new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {
    String value = dataSnapshot.getValue(String.class);
    myCallback.onCallback(value);
    }

    @Override
    public void onCancelled(DatabaseError databaseError) {}
    });
    }


    In the end just simply call readData() method and pass an instance of the MyCallback interface as an argument wherever you need it like this:



    readData(new MyCallback() {
    @Override
    public void onCallback(String value) {
    Log.d("TAG", value);
    }
    });


    This is the only way in which you can use that value outside onDataChange() method. For more information, you can take also a look at this video.







    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited Jul 30 at 13:48

























    answered Dec 17 '17 at 9:26









    Alex Mamo

    38.8k72758




    38.8k72758












    • Can this be achieved using Future interface and Callable? developer.android.com/reference/java/util/concurrent/Future
      – Peter Haddad
      Jul 31 at 16:46










    • Hi Peter! It might work. I didn't tried yet but I will. I don't know if you know this, but here is an interesting article.
      – Alex Mamo
      Jul 31 at 18:25












    • Yes, I saw it before since it is written as a comment in many places. But, I haven't read it, because I know how asynchronous works after reading couple of Q&A here. Anyway, I read it now and I guess it is better not to use Future since we need to use newSingleThreadExecutor() that creates another thread, and since the api is asychronous then it is already in a thread in java and we have to maintain this thread also and write more code.
      – Peter Haddad
      Jul 31 at 19:43










    • @PeterHaddad Firebase client already runs all network operations in a background thread so I think you are right. There is no need for that. Thanks for providing me that resource!
      – Alex Mamo
      Jul 31 at 20:24


















    • Can this be achieved using Future interface and Callable? developer.android.com/reference/java/util/concurrent/Future
      – Peter Haddad
      Jul 31 at 16:46










    • Hi Peter! It might work. I didn't tried yet but I will. I don't know if you know this, but here is an interesting article.
      – Alex Mamo
      Jul 31 at 18:25












    • Yes, I saw it before since it is written as a comment in many places. But, I haven't read it, because I know how asynchronous works after reading couple of Q&A here. Anyway, I read it now and I guess it is better not to use Future since we need to use newSingleThreadExecutor() that creates another thread, and since the api is asychronous then it is already in a thread in java and we have to maintain this thread also and write more code.
      – Peter Haddad
      Jul 31 at 19:43










    • @PeterHaddad Firebase client already runs all network operations in a background thread so I think you are right. There is no need for that. Thanks for providing me that resource!
      – Alex Mamo
      Jul 31 at 20:24
















    Can this be achieved using Future interface and Callable? developer.android.com/reference/java/util/concurrent/Future
    – Peter Haddad
    Jul 31 at 16:46




    Can this be achieved using Future interface and Callable? developer.android.com/reference/java/util/concurrent/Future
    – Peter Haddad
    Jul 31 at 16:46












    Hi Peter! It might work. I didn't tried yet but I will. I don't know if you know this, but here is an interesting article.
    – Alex Mamo
    Jul 31 at 18:25






    Hi Peter! It might work. I didn't tried yet but I will. I don't know if you know this, but here is an interesting article.
    – Alex Mamo
    Jul 31 at 18:25














    Yes, I saw it before since it is written as a comment in many places. But, I haven't read it, because I know how asynchronous works after reading couple of Q&A here. Anyway, I read it now and I guess it is better not to use Future since we need to use newSingleThreadExecutor() that creates another thread, and since the api is asychronous then it is already in a thread in java and we have to maintain this thread also and write more code.
    – Peter Haddad
    Jul 31 at 19:43




    Yes, I saw it before since it is written as a comment in many places. But, I haven't read it, because I know how asynchronous works after reading couple of Q&A here. Anyway, I read it now and I guess it is better not to use Future since we need to use newSingleThreadExecutor() that creates another thread, and since the api is asychronous then it is already in a thread in java and we have to maintain this thread also and write more code.
    – Peter Haddad
    Jul 31 at 19:43












    @PeterHaddad Firebase client already runs all network operations in a background thread so I think you are right. There is no need for that. Thanks for providing me that resource!
    – Alex Mamo
    Jul 31 at 20:24




    @PeterHaddad Firebase client already runs all network operations in a background thread so I think you are right. There is no need for that. Thanks for providing me that resource!
    – Alex Mamo
    Jul 31 at 20:24













    4














    I believe I understand what you are asking. Although you say you want to "return" it (per se) from the fetch method, it may suffice to say you actually just want to be able to use the value retrieved after your fetch has completed. If so, this is what you need to do:




    1. Create a variable at the top of your class

    2. Retrieve your value (which you have done mostly correctly)

    3. Set the public variable in your class equal to value retrieved


    Once your fetch succeeds, you could do many things with the variable. 4a and 4b are some simple examples:



    4a. Edit:
    As an example of use, you can trigger whatever else you need to run in your class that uses yourNameVariable (and you can be sure it yourNameVariable not null)



    4b. Edit:
    As an example of use, you can use the variable in a function that is triggered by a button's onClickListener.





    Try this.



    // 1. Create a variable at the top of your class
    private String yourNameVariable;

    // 2. Retrieve your value (which you have done mostly correctly)
    private void getUserName(String uid) {
    databaseReference.child(String.format("users/%s/name", uid))
    .addListenerForSingleValueEvent(new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {
    // 3. Set the public variable in your class equal to value retrieved
    yourNameVariable = dataSnapshot.getValue(String.class);
    // 4a. EDIT: now that your fetch succeeded, you can trigger whatever else you need to run in your class that uses `yourNameVariable`, and you can be sure `yourNameVariable` is not null.
    sayHiToMe();
    }

    @Override
    public void onCancelled(DatabaseError databaseError) {}
    });
    }

    // (part of step 4a)
    public void sayHiToMe() {
    Log.d(TAG, "hi there, " + yourNameVariable);
    }

    // 4b. use the variable in a function triggered by the onClickListener of a button.
    public void helloButtonWasPressed() {
    if (yourNameVariable != null) {
    Log.d(TAG, "hi there, " + yourNameVariable);
    }
    }


    Then, you can use yourNameVariable wherever you would like throughout your class.





    Note: just be sure you check that yourNameVariable is not null when using it since onDataChange is asynchronous and may not have completed at the time you attempt to use it elsewhere.






    share|improve this answer



















    • 1




      This is an incorrect answer. This is not how thing are going on when it comes to asynchronous methods. Using this answer you'll have your variable yourNameVariable to be always null when using "wherever you would like throughout your class". You can use it only in your onDataChange() method. That's it.
      – Alex Mamo
      Dec 17 '17 at 9:32












    • @AlexMamo, your solution of defining an interface works nicely, but the following part of your comment is incorrect: "yourNameVariable to be always null." For those looking for a more lightweight solution (that does not require defining an interface) this works well. Once the variable has been retrieved and set, they can trigger any functions that need the result and know that the variable is not null (as long as it exists on firebase in the first place). I have updated my example so you can see a concrete use-case.
      – Rbar
      Dec 17 '17 at 19:08












    • Furthermore calling that method has nothing to do with asynchronous behaviour of methods. Calling that method is the same as using this line Log.d(TAG, "hi there, " + yourNameVariable); inside onDataChange() method. This means that when onDataChange() method is triggered you are calling that method.
      – Alex Mamo
      Dec 18 '17 at 8:00












    • @AlexMamo, the function was merely a single example. You can do many other things that do not automatically trigger a funciton. For another simple example, a button could be visible once the data has loaded and triggering the button would do something with the data you have fetched. Again, your example is nice and I am not arguing that it shouldn't be the accepted answer. That being said, your blanket statement (even the full one) of yourNameVariable will be be always null when using "wherever you would like throughout your class". is not true for all cases ... (continued)
      – Rbar
      Dec 18 '17 at 18:47












    • There are several cases in which you could use the value retrieved outside of fetching the data. My point is merely that there is more than one way to skin a cat; some lighter solutions like the one I have posted may work better for some people, and your may work better for many others. No need to get worked up, just sharing knowledge here.
      – Rbar
      Dec 18 '17 at 18:47
















    4














    I believe I understand what you are asking. Although you say you want to "return" it (per se) from the fetch method, it may suffice to say you actually just want to be able to use the value retrieved after your fetch has completed. If so, this is what you need to do:




    1. Create a variable at the top of your class

    2. Retrieve your value (which you have done mostly correctly)

    3. Set the public variable in your class equal to value retrieved


    Once your fetch succeeds, you could do many things with the variable. 4a and 4b are some simple examples:



    4a. Edit:
    As an example of use, you can trigger whatever else you need to run in your class that uses yourNameVariable (and you can be sure it yourNameVariable not null)



    4b. Edit:
    As an example of use, you can use the variable in a function that is triggered by a button's onClickListener.





    Try this.



    // 1. Create a variable at the top of your class
    private String yourNameVariable;

    // 2. Retrieve your value (which you have done mostly correctly)
    private void getUserName(String uid) {
    databaseReference.child(String.format("users/%s/name", uid))
    .addListenerForSingleValueEvent(new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {
    // 3. Set the public variable in your class equal to value retrieved
    yourNameVariable = dataSnapshot.getValue(String.class);
    // 4a. EDIT: now that your fetch succeeded, you can trigger whatever else you need to run in your class that uses `yourNameVariable`, and you can be sure `yourNameVariable` is not null.
    sayHiToMe();
    }

    @Override
    public void onCancelled(DatabaseError databaseError) {}
    });
    }

    // (part of step 4a)
    public void sayHiToMe() {
    Log.d(TAG, "hi there, " + yourNameVariable);
    }

    // 4b. use the variable in a function triggered by the onClickListener of a button.
    public void helloButtonWasPressed() {
    if (yourNameVariable != null) {
    Log.d(TAG, "hi there, " + yourNameVariable);
    }
    }


    Then, you can use yourNameVariable wherever you would like throughout your class.





    Note: just be sure you check that yourNameVariable is not null when using it since onDataChange is asynchronous and may not have completed at the time you attempt to use it elsewhere.






    share|improve this answer



















    • 1




      This is an incorrect answer. This is not how thing are going on when it comes to asynchronous methods. Using this answer you'll have your variable yourNameVariable to be always null when using "wherever you would like throughout your class". You can use it only in your onDataChange() method. That's it.
      – Alex Mamo
      Dec 17 '17 at 9:32












    • @AlexMamo, your solution of defining an interface works nicely, but the following part of your comment is incorrect: "yourNameVariable to be always null." For those looking for a more lightweight solution (that does not require defining an interface) this works well. Once the variable has been retrieved and set, they can trigger any functions that need the result and know that the variable is not null (as long as it exists on firebase in the first place). I have updated my example so you can see a concrete use-case.
      – Rbar
      Dec 17 '17 at 19:08












    • Furthermore calling that method has nothing to do with asynchronous behaviour of methods. Calling that method is the same as using this line Log.d(TAG, "hi there, " + yourNameVariable); inside onDataChange() method. This means that when onDataChange() method is triggered you are calling that method.
      – Alex Mamo
      Dec 18 '17 at 8:00












    • @AlexMamo, the function was merely a single example. You can do many other things that do not automatically trigger a funciton. For another simple example, a button could be visible once the data has loaded and triggering the button would do something with the data you have fetched. Again, your example is nice and I am not arguing that it shouldn't be the accepted answer. That being said, your blanket statement (even the full one) of yourNameVariable will be be always null when using "wherever you would like throughout your class". is not true for all cases ... (continued)
      – Rbar
      Dec 18 '17 at 18:47












    • There are several cases in which you could use the value retrieved outside of fetching the data. My point is merely that there is more than one way to skin a cat; some lighter solutions like the one I have posted may work better for some people, and your may work better for many others. No need to get worked up, just sharing knowledge here.
      – Rbar
      Dec 18 '17 at 18:47














    4












    4








    4






    I believe I understand what you are asking. Although you say you want to "return" it (per se) from the fetch method, it may suffice to say you actually just want to be able to use the value retrieved after your fetch has completed. If so, this is what you need to do:




    1. Create a variable at the top of your class

    2. Retrieve your value (which you have done mostly correctly)

    3. Set the public variable in your class equal to value retrieved


    Once your fetch succeeds, you could do many things with the variable. 4a and 4b are some simple examples:



    4a. Edit:
    As an example of use, you can trigger whatever else you need to run in your class that uses yourNameVariable (and you can be sure it yourNameVariable not null)



    4b. Edit:
    As an example of use, you can use the variable in a function that is triggered by a button's onClickListener.





    Try this.



    // 1. Create a variable at the top of your class
    private String yourNameVariable;

    // 2. Retrieve your value (which you have done mostly correctly)
    private void getUserName(String uid) {
    databaseReference.child(String.format("users/%s/name", uid))
    .addListenerForSingleValueEvent(new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {
    // 3. Set the public variable in your class equal to value retrieved
    yourNameVariable = dataSnapshot.getValue(String.class);
    // 4a. EDIT: now that your fetch succeeded, you can trigger whatever else you need to run in your class that uses `yourNameVariable`, and you can be sure `yourNameVariable` is not null.
    sayHiToMe();
    }

    @Override
    public void onCancelled(DatabaseError databaseError) {}
    });
    }

    // (part of step 4a)
    public void sayHiToMe() {
    Log.d(TAG, "hi there, " + yourNameVariable);
    }

    // 4b. use the variable in a function triggered by the onClickListener of a button.
    public void helloButtonWasPressed() {
    if (yourNameVariable != null) {
    Log.d(TAG, "hi there, " + yourNameVariable);
    }
    }


    Then, you can use yourNameVariable wherever you would like throughout your class.





    Note: just be sure you check that yourNameVariable is not null when using it since onDataChange is asynchronous and may not have completed at the time you attempt to use it elsewhere.






    share|improve this answer














    I believe I understand what you are asking. Although you say you want to "return" it (per se) from the fetch method, it may suffice to say you actually just want to be able to use the value retrieved after your fetch has completed. If so, this is what you need to do:




    1. Create a variable at the top of your class

    2. Retrieve your value (which you have done mostly correctly)

    3. Set the public variable in your class equal to value retrieved


    Once your fetch succeeds, you could do many things with the variable. 4a and 4b are some simple examples:



    4a. Edit:
    As an example of use, you can trigger whatever else you need to run in your class that uses yourNameVariable (and you can be sure it yourNameVariable not null)



    4b. Edit:
    As an example of use, you can use the variable in a function that is triggered by a button's onClickListener.





    Try this.



    // 1. Create a variable at the top of your class
    private String yourNameVariable;

    // 2. Retrieve your value (which you have done mostly correctly)
    private void getUserName(String uid) {
    databaseReference.child(String.format("users/%s/name", uid))
    .addListenerForSingleValueEvent(new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {
    // 3. Set the public variable in your class equal to value retrieved
    yourNameVariable = dataSnapshot.getValue(String.class);
    // 4a. EDIT: now that your fetch succeeded, you can trigger whatever else you need to run in your class that uses `yourNameVariable`, and you can be sure `yourNameVariable` is not null.
    sayHiToMe();
    }

    @Override
    public void onCancelled(DatabaseError databaseError) {}
    });
    }

    // (part of step 4a)
    public void sayHiToMe() {
    Log.d(TAG, "hi there, " + yourNameVariable);
    }

    // 4b. use the variable in a function triggered by the onClickListener of a button.
    public void helloButtonWasPressed() {
    if (yourNameVariable != null) {
    Log.d(TAG, "hi there, " + yourNameVariable);
    }
    }


    Then, you can use yourNameVariable wherever you would like throughout your class.





    Note: just be sure you check that yourNameVariable is not null when using it since onDataChange is asynchronous and may not have completed at the time you attempt to use it elsewhere.







    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited Dec 18 '17 at 19:03

























    answered Dec 17 '17 at 3:19









    Rbar

    98611234




    98611234








    • 1




      This is an incorrect answer. This is not how thing are going on when it comes to asynchronous methods. Using this answer you'll have your variable yourNameVariable to be always null when using "wherever you would like throughout your class". You can use it only in your onDataChange() method. That's it.
      – Alex Mamo
      Dec 17 '17 at 9:32












    • @AlexMamo, your solution of defining an interface works nicely, but the following part of your comment is incorrect: "yourNameVariable to be always null." For those looking for a more lightweight solution (that does not require defining an interface) this works well. Once the variable has been retrieved and set, they can trigger any functions that need the result and know that the variable is not null (as long as it exists on firebase in the first place). I have updated my example so you can see a concrete use-case.
      – Rbar
      Dec 17 '17 at 19:08












    • Furthermore calling that method has nothing to do with asynchronous behaviour of methods. Calling that method is the same as using this line Log.d(TAG, "hi there, " + yourNameVariable); inside onDataChange() method. This means that when onDataChange() method is triggered you are calling that method.
      – Alex Mamo
      Dec 18 '17 at 8:00












    • @AlexMamo, the function was merely a single example. You can do many other things that do not automatically trigger a funciton. For another simple example, a button could be visible once the data has loaded and triggering the button would do something with the data you have fetched. Again, your example is nice and I am not arguing that it shouldn't be the accepted answer. That being said, your blanket statement (even the full one) of yourNameVariable will be be always null when using "wherever you would like throughout your class". is not true for all cases ... (continued)
      – Rbar
      Dec 18 '17 at 18:47












    • There are several cases in which you could use the value retrieved outside of fetching the data. My point is merely that there is more than one way to skin a cat; some lighter solutions like the one I have posted may work better for some people, and your may work better for many others. No need to get worked up, just sharing knowledge here.
      – Rbar
      Dec 18 '17 at 18:47














    • 1




      This is an incorrect answer. This is not how thing are going on when it comes to asynchronous methods. Using this answer you'll have your variable yourNameVariable to be always null when using "wherever you would like throughout your class". You can use it only in your onDataChange() method. That's it.
      – Alex Mamo
      Dec 17 '17 at 9:32












    • @AlexMamo, your solution of defining an interface works nicely, but the following part of your comment is incorrect: "yourNameVariable to be always null." For those looking for a more lightweight solution (that does not require defining an interface) this works well. Once the variable has been retrieved and set, they can trigger any functions that need the result and know that the variable is not null (as long as it exists on firebase in the first place). I have updated my example so you can see a concrete use-case.
      – Rbar
      Dec 17 '17 at 19:08












    • Furthermore calling that method has nothing to do with asynchronous behaviour of methods. Calling that method is the same as using this line Log.d(TAG, "hi there, " + yourNameVariable); inside onDataChange() method. This means that when onDataChange() method is triggered you are calling that method.
      – Alex Mamo
      Dec 18 '17 at 8:00












    • @AlexMamo, the function was merely a single example. You can do many other things that do not automatically trigger a funciton. For another simple example, a button could be visible once the data has loaded and triggering the button would do something with the data you have fetched. Again, your example is nice and I am not arguing that it shouldn't be the accepted answer. That being said, your blanket statement (even the full one) of yourNameVariable will be be always null when using "wherever you would like throughout your class". is not true for all cases ... (continued)
      – Rbar
      Dec 18 '17 at 18:47












    • There are several cases in which you could use the value retrieved outside of fetching the data. My point is merely that there is more than one way to skin a cat; some lighter solutions like the one I have posted may work better for some people, and your may work better for many others. No need to get worked up, just sharing knowledge here.
      – Rbar
      Dec 18 '17 at 18:47








    1




    1




    This is an incorrect answer. This is not how thing are going on when it comes to asynchronous methods. Using this answer you'll have your variable yourNameVariable to be always null when using "wherever you would like throughout your class". You can use it only in your onDataChange() method. That's it.
    – Alex Mamo
    Dec 17 '17 at 9:32






    This is an incorrect answer. This is not how thing are going on when it comes to asynchronous methods. Using this answer you'll have your variable yourNameVariable to be always null when using "wherever you would like throughout your class". You can use it only in your onDataChange() method. That's it.
    – Alex Mamo
    Dec 17 '17 at 9:32














    @AlexMamo, your solution of defining an interface works nicely, but the following part of your comment is incorrect: "yourNameVariable to be always null." For those looking for a more lightweight solution (that does not require defining an interface) this works well. Once the variable has been retrieved and set, they can trigger any functions that need the result and know that the variable is not null (as long as it exists on firebase in the first place). I have updated my example so you can see a concrete use-case.
    – Rbar
    Dec 17 '17 at 19:08






    @AlexMamo, your solution of defining an interface works nicely, but the following part of your comment is incorrect: "yourNameVariable to be always null." For those looking for a more lightweight solution (that does not require defining an interface) this works well. Once the variable has been retrieved and set, they can trigger any functions that need the result and know that the variable is not null (as long as it exists on firebase in the first place). I have updated my example so you can see a concrete use-case.
    – Rbar
    Dec 17 '17 at 19:08














    Furthermore calling that method has nothing to do with asynchronous behaviour of methods. Calling that method is the same as using this line Log.d(TAG, "hi there, " + yourNameVariable); inside onDataChange() method. This means that when onDataChange() method is triggered you are calling that method.
    – Alex Mamo
    Dec 18 '17 at 8:00






    Furthermore calling that method has nothing to do with asynchronous behaviour of methods. Calling that method is the same as using this line Log.d(TAG, "hi there, " + yourNameVariable); inside onDataChange() method. This means that when onDataChange() method is triggered you are calling that method.
    – Alex Mamo
    Dec 18 '17 at 8:00














    @AlexMamo, the function was merely a single example. You can do many other things that do not automatically trigger a funciton. For another simple example, a button could be visible once the data has loaded and triggering the button would do something with the data you have fetched. Again, your example is nice and I am not arguing that it shouldn't be the accepted answer. That being said, your blanket statement (even the full one) of yourNameVariable will be be always null when using "wherever you would like throughout your class". is not true for all cases ... (continued)
    – Rbar
    Dec 18 '17 at 18:47






    @AlexMamo, the function was merely a single example. You can do many other things that do not automatically trigger a funciton. For another simple example, a button could be visible once the data has loaded and triggering the button would do something with the data you have fetched. Again, your example is nice and I am not arguing that it shouldn't be the accepted answer. That being said, your blanket statement (even the full one) of yourNameVariable will be be always null when using "wherever you would like throughout your class". is not true for all cases ... (continued)
    – Rbar
    Dec 18 '17 at 18:47














    There are several cases in which you could use the value retrieved outside of fetching the data. My point is merely that there is more than one way to skin a cat; some lighter solutions like the one I have posted may work better for some people, and your may work better for many others. No need to get worked up, just sharing knowledge here.
    – Rbar
    Dec 18 '17 at 18:47




    There are several cases in which you could use the value retrieved outside of fetching the data. My point is merely that there is more than one way to skin a cat; some lighter solutions like the one I have posted may work better for some people, and your may work better for many others. No need to get worked up, just sharing knowledge here.
    – Rbar
    Dec 18 '17 at 18:47











    2














    Here's a crazy Idea, inside onDataChange, put it inside a TextView with visibility gone
    textview.setVisiblity(Gone) or something, XD
    then do something like



    textview.setText(dataSnapshot.getValue(String.class))




    then later get it with textview.getText().toString()



    just a crazy simple Idea.






    share|improve this answer




























      2














      Here's a crazy Idea, inside onDataChange, put it inside a TextView with visibility gone
      textview.setVisiblity(Gone) or something, XD
      then do something like



      textview.setText(dataSnapshot.getValue(String.class))




      then later get it with textview.getText().toString()



      just a crazy simple Idea.






      share|improve this answer


























        2












        2








        2






        Here's a crazy Idea, inside onDataChange, put it inside a TextView with visibility gone
        textview.setVisiblity(Gone) or something, XD
        then do something like



        textview.setText(dataSnapshot.getValue(String.class))




        then later get it with textview.getText().toString()



        just a crazy simple Idea.






        share|improve this answer














        Here's a crazy Idea, inside onDataChange, put it inside a TextView with visibility gone
        textview.setVisiblity(Gone) or something, XD
        then do something like



        textview.setText(dataSnapshot.getValue(String.class))




        then later get it with textview.getText().toString()



        just a crazy simple Idea.







        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited Nov 14 at 18:53









        VenomVendor

        10.3k105182




        10.3k105182










        answered Aug 1 at 13:08









        klaid bendio Moran

        211




        211






























            draft saved

            draft discarded




















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.





            Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


            Please pay close attention to the following guidance:


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f47847694%2fhow-to-return-datasnapshot-value-as-a-result-of-a-method%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            404 Error Contact Form 7 ajax form submitting

            How to know if a Active Directory user can login interactively

            Refactoring coordinates for Minecraft Pi buildings written in Python