Can't get Firestore to return a field value from a collection in Android Studio
Any code that needs to have access to the data from the database, has to be inside the completion listener that gets called when that data is available.
So:
docRef.get().addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
@Override
public void onComplete(@NonNull Task<DocumentSnapshot> task) {
if (task.isSuccessful()) {
DocumentSnapshot document = task.getResult();
if (document.exists()) {
String dbValue = document.getString("password");
tvMenu.setText(dbValue); // br> } else {
Log.d("TAG", "No such document");
}
} else {
Log.d("TAG", "get failed with ", task.getException());
}
}
});
For more on this, see:
- How to check a certain data already exists in firestore or not
- Why does my function that calls an API or launches a coroutine return an empty or null value?
- How to return a DocumentSnapShot as a result of a method?
- getContactsFromFirebase() method return an empty list
- Setting Singleton property value in Firebase Listener
My function iss returning a value before the code in the inner class finishes
From the docs:
onDataChange
: This method will be called with a snapshot of the data at this location. It will also be called each time that data changes.
When the data changes, whatever is inside the method will be executed. In other words, the method onDataChange
instructs the program what to do when it gets results (which could be whenever)
This is asynchronous behaviour - as @Turing85 points out, this will only be called when the data changes.
If you want to know if something with this key exists, you could construct a query and then call get()
method which would return a Task<DataSnapshot>
. For this task, you could attach addOnCompleteListener
listener to do what you would like. This would also be asynchronous, so it would only run when there is a result.
Return is not returning the value
Your original code was incorrect because it fires off an asynchronous function to the API and then returns immediately, before that asynchronous work is done and has fired its callback to update the bitmap
property.
Your second code is wrong, because it tries to resume the continuation with the value of the property bitmap
, which you have not updated with the value that was returned in the callback. Also, since you're just wanting a Bitmap from the cloud file, there's no reason to download it to a temporary file. You can work directly with the bytes. And there's no reason to use a property that I can see. bitmap
can be a local variable.
Also, since you don't do anything in case of failure, your function would hang if there is a problem retrieving the data from Firebase. Below, I just throw the error, but you could do something different like returning null if you want.
I don't know what you're doing with those two parameters, but I left them. I leave it up to you to decide what your byte limit should be (I just used 5 million bytes). I don't remember the guaranteed minimum amount of available memory is for an Android app, and you might know that the file you're retrieving is below that value anyway.
override suspend fun retrive(doc_name: String, uid: String): Bitmap = suspendCoroutine { cont ->
val storageRef =
FirebaseStorage.getInstance().reference.child("/image/0XhL4jD4XCemk38rcRkIEjJMgjh2/Aadhar")
storageRef.getBytes(5_000_000L).addOnSuccessListener { byteArray ->
val bitmap = BitmapFactory.decodeByteArray(byteArray)
cont.resume(bitmap)
}.addOnFailureListener {
cont.resumeWithException(it)
}
}
However: Firebase already comes with the await()
extension suspend function so you don't have to use suspendCoroutine
.
override suspend fun retrive(doc_name: String, uid: String): Bitmap {
val storageRef =
FirebaseStorage.getInstance().reference.child("/image/0XhL4jD4XCemk38rcRkIEjJMgjh2/Aadhar")
val byteArray = storageRef.getBytes(5_000_000L).await()
return BitmapFactory.decodeByteArray(byteArray)
}
Since decoding a bitmap is kind of a heavy operation, I would do this in Dispatchers.Default
:
override suspend fun retrive(doc_name: String, uid: String): Bitmap = withContext(Dispatchers.Default) {
val storageRef =
FirebaseStorage.getInstance().reference.child("/image/0XhL4jD4XCemk38rcRkIEjJMgjh2/Aadhar")
val byteArray = storageRef.getBytes(5_000_000L).await()
return BitmapFactory.decodeByteArray(byteArray)
}
Related Topics
Sending Email in Android Using Javamail API Without Using the Default/Built-In App
How to Add a Timestamp in Firestore With Android
How to Make an Android Device Vibrate? With Different Frequency
How to Deal With Linkageerrors in Java
How to Use Java.Net.Urlconnection to Fire and Handle Http Requests
Avoiding Nullpointerexception in Java
How to Get the Path of a Running Jar File
Why Doesn't Java Allow Overriding of Static Methods
How to Get the User Input in Java
Collision Detection With Complex Shapes
Remove Top-Level Container on Runtime
How to Create a Memory Leak in Java
Efficiency of Java "Double Brace Initialization"
String Concatenation: Concat() VS "+" Operator