How to handle timeout in queries with Firebase
Solution 1
you can manage yourself a timer controller that after x seconds remove the listener to you firebase reference. It's very simple, just one line of code in android for example.
You can see the code for the web (Detaching Callbacks section): https://www.firebase.com/docs/web/guide/retrieving-data.html
or for android (Detaching Callbacks section): https://www.firebase.com/docs/android/guide/retrieving-data.html#section-detaching
same section for IOS ;)
Solution 2
As per today there is no timeout concept on those listeners. One option is to manage the timeout yourself.
This is how I do it when I also want to display a progress dialog while loading the content.
private void showProgressDialog(boolean show, long time) {
try {
if (progressDialog != null) {
if (show) {
progressDialog.setMessage("Cargando...");
progressDialog.show();
new Handler().postDelayed(new Runnable() {
public void run() {
if(progressDialog!=null && progressDialog.isShowing()) {
progressDialog.dismiss();
Toast.makeText(ActPreguntas.this, "Couldn't connect, please try again later.", Toast.LENGTH_LONG).show();
}
}
}, time);
} else {
progressDialog.dismiss();
}
}
}catch(IllegalArgumentException e){
}catch(Exception e){
}
}
So when you make a request to Firebase you call showProgressDialog(true,5000) and after 5 seconds if the dialog stills there is because it could not connect and you then do what you have to as per the timeout.
On the callback of the Firebase listener you do this showProgressDialog(false,0)
Hope it helps.
Solution 3
Here's my solution for the Firebase iOS SDK, this may be helpful for others:
extension DatabaseReference {
func observe(_ eventType: DataEventType, timeout: TimeInterval, with block: @escaping (DataSnapshot?) -> Void) -> UInt {
var handle: UInt!
let timer = Timer.scheduledTimer(withTimeInterval: timeout, repeats: false) { (_) in
self.removeObserver(withHandle: handle)
block(nil)
}
handle = observe(eventType) { (snapshot) in
timer.invalidate()
block(snapshot)
}
return handle
}
}
Usage:
database.child("users").observe(.value, timeout: 30) { (snapshot) in
guard let snapshot = snapshot else {
// Timeout!
return
}
// We got data within the timeout, so do something with snapshot.value
}
magicwerk
Updated on June 11, 2022Comments
-
magicwerk about 2 years
I noticed that if I execute a query in Firebase and the database server is not reachable, the callback waits just forever (or until the server is reachable again).
Where this behavior is quite natural for the asynchronous approach used, it would nevertheless be useful to have an easy way to specify a timeout so you could inform the user about the status.
Is there such an option and I just missed it - or it really missing? Or how would you solve this problem?
-
Amit almost 8 yearsobserveSingleEventOfType, with this we don't get a handle and hence won't be able to detach the callback.
-
justintime almost 6 yearsIsn't it better to remove the listener on completing five seconds? Alternatively, we can bake in the timeout feature into the request itself instead of tying it to a UI component.
-
Jonathan Ellis almost 4 yearsThe documentation states: "This setting does not affect the FirebaseDatabase and FirestoreClient APIs." There also seems to be no equivalent option for iOS.