(Disclaimer: There's a ton of questions which arise from people asking about data being null/incorrect when using asynchronous operations through requests such as facebook,firebase, etc. My intentions for this question was to provide a simple answer for that problem to everyone starting out with asynchronous operations in android, as I couldn't really find an example of this after searching)
I'm trying to get data from one of my operations, when I debug it, the values are there, but when I run it they are always null, how can I solve this ?
Firebase
firebaseFirestore.collection("some collection").get()
.addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
@Override
public void onSuccess(QuerySnapshot documentSnapshots) {
//I want to get these values here?
})
Facebook
GraphRequest request = GraphRequest.newGraphPathRequest(
accessToken,
"some path",
new GraphRequest.Callback() {
@Override
public void onCompleted(GraphResponse response) {
//I want to get these values here?
}
});
request.executeAsync();
What is a Synchronous/Asynchronous operation ?
Well, Synchronous waits until the task has completed. Your code executes "top-down" in this situation.
Asynchronous completes a task in the background and can notify you when it is complete.
To get your values from an async operation, you can define your own callbacks in your methods to use these values as they are returned from these operations.
Here's how for Java
Start off by defining an interface :
interface Callback {
void myResponseCallback(YourReturnType result);//whatever your return type is: string, integer, etc.
}
next, change your method signature to be like this :
public void foo(final Callback callback) { // make your method, which was previously returning something, return void, and add in the new callback interface.
next up, wherever you previously wanted to use those values, add this line :
callback.myResponseCallback(yourResponseObject);
as an example :
@Override
public void onSuccess(QuerySnapshot documentSnapshots) {
// create your object you want to return here
String bar = document.get("something").toString();
callback.myResponseCallback(bar);
})
now, where you were previously calling your method called foo
:
foo(new Callback() {
@Override
public void myResponseCallback(YourReturnType result) {
//here, this result parameter that comes through is your api call result to use, so use this result right here to do any operation you previously wanted to do.
}
});
}
How do you do this for Kotlin ?
(as a basic example where you only care for a single result)
start off by changing your method signature to something like this:
fun foo(callback:(YourReturnType) -> Unit) {
.....
then, inside your asynchronous operation's result :
firestore.collection("something").document("document").get().addOnSuccessListener {
val bar = it.get("something").toString()
callback.invoke(bar)
}
then, where you would have previously called your method called foo
, you now do this :
foo { result->
here, this result parameter that comes through is your api call result to use, so use this result right here to do any operation you previously wanted to do.
}
if your foo
method previously took in parameters :
fun foo(value:SomeType, callback:(YourType) -> Unit)
you simply change it to :
foo(yourValueHere) { result ->
here, this result parameter that comes through is your api call result to use, so use this result right here to do any operation you previously wanted to do.
}