Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

My Flutter app with Firestore experiences very slow queries when it is resumed from the background on Android

Using Flutter 1.20.2.

My Flutter app uses Firestore as it's backend database. For the current version I am using and throughout the development of this mobile app I have noticed that if my app is in the background for a period of time (could be a few mins) then when I bring the app back into the foreground the queries are very slow to return data. This does not happen on iOS. It only happens on Android.

I use CircularProgressIndicators when my app is busy retrieving data from Firestore. I am using a solid state management setup where each of my Views have a model that extends a BaseModel:

class BaseModel extends ChangeNotifier {
  ViewState _state = ViewState.Idle;
  ViewState get state => _state;
  bool isDisposed = false;

  void setState(ViewState viewState) {
    _state = viewState;
    if (!isDisposed) {
      notifyListeners();
    }
  }

  @override
  void dispose() {
    isDisposed = true;
    super.dispose();
  }
}

My views then use my view specific models in the following way:

  @override
  Widget build(BuildContext context) {
    return BaseView<MyProfileModel>(
        //onModelReady: (model) => model.initialise(Provider.of<User>(context, listen: false)),
        onModelReady: (model) => model.initialise(),
        builder: (context, model, child) => Scaffold(
              resizeToAvoidBottomInset: false,
...

I do not use the AppLifecycleState class yet to do anything special when the app is in the background or is resumed from the background.

When my model is busy retrieving data I show busy circular progress indicators.

The issue is that when I resume my app from the background into the foreground, sometimes the app could be busy for up to 1 minute before it retrieves the data - but only the first time after being back in the foreground. All subsequent calls are normal. Sometimes, it even hangs on first attempt to get data after coming back to the foreground.

I feel like I am not implementing a best practice in relation to resuming an app into the foreground that uses the Firestore database. I have a suspicion that it has something to do with re-establishing the Firestore connection and/or local cache. My App uses the default settings for these.

All of my Firestore API calls are contained in it's own class and I call it the same way each time:

    await Firestore.instance
        .collection(DBStrings.COLLECTION_AD_MESSAGES)
        .document(ad.adId)
        .collection(DBStrings.COLLECTION_CHILD_AD_MESSAGES)
        .document()
        .setData({
        // Set fields...
    }).catchError((e) {
      res = false;
    });

Can someone give me some insight into this issue and what could be potentially causing it?

like image 844
Arturo Knight Avatar asked Aug 16 '20 08:08

Arturo Knight


People also ask

Why is firestore query slow?

Probably the most common explanation for a seemingly slow query is that your query is, in fact, running very fast. But after the query is complete, we still need to transfer all of that data to your device, and that's the part that's running slowly.

Is Firebase good for Flutter?

Firebase is one of those perfect matches for mobile app development as well as for Flutter.

Why Firebase is best for Flutter?

The Firebase real-time database, ready-made authentication options along with the Flutter in-built widgets and a single code for Android and iOS make the whole healthcare software development process faster while maintaining the solution's safety and performance.

How do I make Firebase faster?

A quick approach to hide that latency is by making use of Firebase's built-in caching. When you call getDocuments , the Firebase client needs to check on the server what the document's value is before it can call your code, which then shows the value to the user.


1 Answers

It seem to me that your app is loosing the connection and the data retrieved is from the cache. My suggestion is for you to try to change the backend data from the Firebase console while your app is in the background, then test to see if the retrieved data is the updated or the old one.

If the data is the old one, it means your app could not restore the connection. To overcome this problem you need to check the auth status (if used) and to check the connection status. A simple way to identify connection status and not allow the app to take a very long time before going cache, is to force the app to ask data from remote and provide a timeout, like this:

QuerySnapshot snapshot = await query.getDocuments(source: Source.server).timeout(
        _timeoutDuration,
        // this or any other callback to handle timeout
        onTimeout: () => query.getDocuments(source: Source.cache));

If you are using auth, you can check the auth status by calling:

FirebaseUser currentUser = await _auth.currentUser();
if (currentUser != null) {
  // Handle your auth problem here
}

If you are not using auth and the app is retrieving the data from the server after this long period, check if the app would come back faster without the firebase query.

like image 188
Rod Avatar answered Nov 15 '22 06:11

Rod