Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flutter Firestore take long retrieving data while offline

I am using Firestore in flutter application. Each time user launch the application it retrieves some data from Firestore Cloud.

QuerySnapshot dataSnapshot = await Firestore.instance
        .collection('/data')
        .getDocuments();

When user opens the application on first time, it required from him to connect online, to get the data, and as Firebase documents say

For Android and iOS, offline persistence is enabled by default. To disable persistence, set the PersistenceEnabled option to false.

So, it should save the data that application have been read before to retrieve it while the device is offline; so user can access application at anytime with the same data that have been read.

The problem is: it takes too long time to retrieve the data while the device is offline, with the same codes and nothing changed!.

I tried to configure how much time it takes? On offline, it takes about 8 minutes and 40 seconds. But while on online, it takes just 10 seconds, maybe less.

So how can I solve this problem?

============

UPDATE

I manged to get more logs about this problem, which after take a lot of time, and will start application with the offline saved data, it prints this log

This typically indicates that your device does not have a healthy Internet connection at the moment. The client will operate in offline mode until it is able to successfully connect to the backend.

And then take 3 second for example (not much time) and continue with the next works.

I did open a new issue in GitHub too.

Is there a way to limit the time it takes?

like image 995
Shady Boshra Avatar asked Mar 30 '19 21:03

Shady Boshra


1 Answers

And finally, with the help of diegoveloper comment in GitHub issue, I have reached the solution.

This comment

await Firestore.instance .collection("Collection") .getDocuments(source: source)

was a good solution if I decided to check source each time and then use it or I can use it in starting of a new Flutter project, but now I already have a lot of codes that need a better solution. So I decided to fork the cloud_firestore package and edit it.

You can find it here: https://github.com/ShadyBoshra2012/flutterfire/tree/master/packages/cloud_firestore

What I have edited:

  1. firestore.dart
// The source of which the data will come from.
 static Source _source = Source.serverAndCache;

 static Source get source => _source;

 Future<void> settings(
     {bool persistenceEnabled,
     String host,
     bool sslEnabled,
     bool timestampsInSnapshotsEnabled,
     int cacheSizeBytes,
     Source source}) async {
   await channel.invokeMethod<void>('Firestore#settings', <String, dynamic>{
     'app': app.name,
     'persistenceEnabled': persistenceEnabled,
     'host': host,
     'sslEnabled': sslEnabled,
     'timestampsInSnapshotsEnabled': timestampsInSnapshotsEnabled,
     'cacheSizeBytes': cacheSizeBytes,
   });
   if (source != null) _source = source;
 }
  1. query.dart source = Firestore.source; Line 92

  2. document_reference.dart source = Firestore.source; Line 83

How you can use it?

So you can use my forked repository in this way with using connectivity package from Google : https://pub.dev/packages/connectivity .

Add my forked repository in pubspec.yaml file

cloud_firestore:
    git:
      url: https://github.com/ShadyBoshra2012/flutterfire.git
      path: packages/cloud_firestore

Then in your first screen or main

var connectivityResult = await (Connectivity().checkConnectivity());
if (connectivityResult == ConnectivityResult.none) {
    await Firestore.instance.settings(source: Source.cache);
} else {
    await Firestore.instance.settings(source: Source.serverAndCache);
}

and if you want to refresh the source when change the connection state:

StreamSubscription subscription;

void initState() {
    super.initState();
    // Check the internet connection after each change
    // of the connection.
    subscription = Connectivity()
        .onConnectivityChanged
        .listen((ConnectivityResult result) async {
      // Check the internet connection and then choose the appropriate
      // source for it.
      var connectivityResult = await (Connectivity().checkConnectivity());
      if (connectivityResult == ConnectivityResult.none) {
        await Firestore.instance.settings(source: Source.cache);
      } else {
        await Firestore.instance.settings(source: Source.serverAndCache);
      }
    });
}

@override
  void dispose() {
    super.dispose();
    subscription.cancel();
  }

So I hope it works with everyone see it, and waiting for Flutter Team to code a better and better solution. Thanks for everyone has participated.

like image 157
Shady Boshra Avatar answered Nov 15 '22 05:11

Shady Boshra