Flutterfire: [cloud_firestore] Cloud Firestore calls are blocking UI thread

Created on 10 Oct 2019  路  17Comments  路  Source: FirebaseExtended/flutterfire

Describe the bug
I have an application that uses cloud firestore and it seems the execution of the plugin code is blocking the main thread.

To Reproduce
I have something like the following to listen for document updates:

_firestore.collection('collectionName').where('key', isEqualTo: 'dummyKey').snapshots().map((QuerySnapshot snapshot) {
  // Process records
});

I have something like the following to update a record:

final Map<String, dynamic> updateData = <String, dynamic>{};
.
.
.
_firestore.collection('collectionName').document('dummyId').updateData(updateData);

When I call the code to update a record, it takes quite a while to return anything from the listener (not sure why because it is only returning ~250 records, but that is a separate issue). During this time, the UI thread seems to be blocked. Any loading animations I try to show during this I/O time just freeze on the screen. How can I execute cloud firestore I/O operations and not block the UI thread?

Expected behavior
Execution of the cloud firestore plugin code should not block the main dart UI thread.

crowd cloud_firestore bug

Most helpful comment

Any updates on this issue?
I trying to call getDocuments method (there are 30,000+ docs in my collection), and this method blocking my UI thread.

All 17 comments

@jonjon1123 Have you tried on release build? Debug build are generally slower

Yes, it does return the result back faster in release or profile mode, but it still blocks the main UI thread -- something that should be avoided as a best practice. I would like a way for I/O intensive operations like this to not block the main UI thread.

I am facing the same issue. It is occurring when my firestore collection has 200-300 document and it is continuously added,deleted or updated.It is causing a lot of GC run which eventually pauses the main thread

Any updates on this issue?
I trying to call getDocuments method (there are 30,000+ docs in my collection), and this method blocking my UI thread.

This will get fixed when the API is reviewed.

I have the same issue, and I see that some guys tried to use a separate isolate:

https://stackoverflow.com/questions/56728050/running-firestore-methods-in-a-flutter-isolate-throws-exception
https://stackoverflow.com/questions/59120325/cannot-execute-firebase-query-within-isolate

I was trying to do a similar thing, but just using compute, an example here https://flutter.dev/docs/cookbook/networking/background-parsing, but it doesn't work for me.

is anybody knows how to correctly move firestore work to a separate isolate?

in this article https://flutter.dev/docs/cookbook/networking/background-parsing I see this note:
_"You might experience errors if you try to pass more complex objects, such as a Future or http.Response between isolates."_
so it is very possible that firestore cannot be used in a separate isolate, but it will be good if someone can confirm it.

thanks in advance!

Same issue too.
I have a collection of hundreds documents, and when I add a document in it, the UI freezes about 100~200 ms. If I add several docs continuously, UI completely stops during the process.

there are 30,000+ docs in my collection

Generally you should probably be breaking this up into paginated calls or structuring your data in a way which allows you to perform less calls.

Threading will only solve part of the problem - if you're pushing through a massive volume of data, you'll see performance hits whether it's on a separate thread or not (since it will consume a lot of device resource).

That being said, the work carried out in #2582 does already address this and is the first plugin being worked on.

The parseQuerySnapshot method above will be the bottleneck since it has to iterate data into a codec friendly format. This work has been shifted into a separate thread but as mentioned above, you'll always have performance degradation with such a massive volume of documents.

This code blocks the thread await Firestore.instance.collection(collection).document(id).updateData(data);

Don't know if I have the same problem. But if device is offline, it seems it blocks the thread it's running in (UI still responses to interactions). When device backs to online, all events start emitting like crazy.

Note that I have only some documents.

I replace with my own stream, created from StreamController.broadcast() and everything works. So it must be a problem from cloud_firestore. I am using cloud_firestore 0.13.7

Hey all, as part of our on-going work for #2582, our Firebase Firestore rework (#2913) has had some work done which moves various parsing logic on native to a different thread - which has now been merged into master. We'll look at publishing some prereleases in the next few days. Thank you

This code blocks the thread await Firestore.instance.collection(collection).document(id).updateData(data);

Don't know if I have the same problem. But if device is offline, it seems it blocks the thread it's running in (UI still responses to interactions). When device backs to online, all events start emitting like crazy.

Note that I have only some documents.

I replace with my own stream, created from StreamController.broadcast() and everything works. So it must be a problem from cloud_firestore. I am using cloud_firestore 0.13.7

It looks like that await is not needed during updates, because data will be added immediately to a local cache, and you don't need to wait while server will confirm that data was successfully added on the Firestore side

check out this part:
https://youtu.be/XrltP8bOHT0?t=674

it is very possible that it shouldn't not work this way and should not block the thread in this cases as well, but once I removed await from all add/update operations in my code it started working as expected for me even in Offline mode.

it is very possible that it shouldn't not work this way and should not block the thread in this cases as well, but once I removed await from all add/update operations in my code it started working as expected for me even in Offline mode.

It is the way it's supposed to work. As you hint, the futures would never resolve in offline mode. Their official recommendation is to never wait for the server.

If you want to know when the data has been written to the remote server, wait for the promise to resolve.

Generally if you're using await things will be blocked until this has been done. The other alternative is to handle it with .then:

Firestore.instance.collection(collection).document(id).updateData(data)
    .then(() => // do something when server is called );

... // Do other stuff

Generally if you're using await things will be blocked until this has been done.

Regardless how to deal with Future, I wonder why updateData in offline mode could not return after saving to local database? Is there any impediment here to do that in the library?

Generally if you're using await things will be blocked until this has been done.

Regardless how to deal with Future, I wonder why updateData in offline mode could not return after saving to local database? Is there any impediment here to do that in the library?

basically you don't need to wait for these things, in my case for example I always keep data in memory, because parsing JSON in some cases also takes some time, so don't need to know exactly when data will be saved to Firestore local cache on device storage, because I can get this new data from memory.

so in my cases I work with Firestore this way:

  1. load data from Firestore, parse JSON and store plain object in memory
  2. listen for any remote adds/updates - and then add/update only these objects in memory
  3. all added or updated objects will be then added / updated in memory, and also saved to Firestore without await
  4. consume added or updated objects directly from memory, do not use Firestore for these things.

I hope it helps.

@perepechin Sure that without waiting add/update, we can continue the app by listening to the changes.

But the library still shouldn't block the thread.
Developers, especially new flutter developers, should not worry about this problem.

Was this page helpful?
0 / 5 - 0 ratings