Randomizing data with Flutter and Firebase. My walkthrough of various solutions.

0 25
Avatar for nolyoi
Written by
3 years ago
Topics: Programming, Flutter, Dart, Code, Coding, ...

So, recently while working on the Skica Flutter application, I struggled with a problem of randomizing data and calling it the way I wanted to. Below goes through the various transformations of my code

The 'tips' Cloudstore collection reference, a Random, and a 'next' function that randomizes a number between a given min and max range.

class _TipsCardState extends State<TipsCard> {
  CollectionReference tips = FirebaseFirestore.instance.collection('tips');
  final _random = new Random();
  String next(int min, int max) =>
      (min + _random.nextInt(max - min)).toString();
  String _randomTip;
  int _tipsCount;

  Future<int> countDocuments() async {
    QuerySnapshot _myDoc = await tips.get();
    List<DocumentSnapshot> _myDocCount = _myDoc.docs;
    print(_myDocCount.length);
    return _myDocCount.length;
  }

  Future<DocumentSnapshot> getTips() async {
    _tipsCount = await countDocuments();
    _randomTip = next(1, _tipsCount);

    return await tips.doc(_randomTip).get();
  }

The problem I ran in to was trying to accomplish this all in a single function. There really is no reason to over complicate functions. Though, I'm pretty sure it can be done, it's better to just seperate things if it makes the code more readable, imo.

First is the countDocuments function.

This one is very simple. We're simply querying the Tips Collection, then getting the documents that belong to that collection and returning it's length. This gives us the amount of Documents in the Tips Collection.

Note: In Firestore, a Collection contains Documents.

In the body of the app, the getTips function is called within a FutureBuilder widget. Since it returns the DocumentSnapshot of the database.

But! I ended up simplifying this even more by using a provider! I added a StreamProvder<Tip> to my app's MultiProvider like so. The code to randomize the tips remains the same, however now I manually set the range instead of generating it. dynamically. No biggie.

class App extends StatelessWidget {
  static FirebaseAnalytics analytics = FirebaseAnalytics();
  final _random = new Random();
  String next(int min, int max) =>
      (min + _random.nextInt(max - min)).toString();
  String _randomTip;

  @override
  Widget build(BuildContext context) {
    _randomTip = next(1, 33);
    return MultiProvider(
      providers: [
        ChangeNotifierProvider<AuthProvider>(create: (_) => AuthProvider()),
        StreamProvider<User>.value(
          value: FirebaseAuth.instance.authStateChanges(),
        ),
        StreamProvider<Tip>.value(
          value: TipProvider().streamTip(_randomTip),
        ),
      ],

The StreamProvider's value is TipProvider().streamTip(_randomTip) which is the following code below:

class TipProvider with ChangeNotifier {
  final String uid;
  TipProvider({this.uid});
  final FirebaseFirestore firestore = FirebaseFirestore.instance;
  bool loading = false;

  Stream<Tip> streamTip(String id) {
    return firestore
        .collection('tips')
        .doc(id)
        .snapshots()
        .map((snap) => Tip.fromFirestore(snap));
  }

The TipProvider also contains other useful methods related to tips such as addTipLikeremoveTipLikeaddTipBookmarkremoveTipBookmark, etc.

This is a much more clean way of organizing this code, imo. We can store methods/functions related to the Tips in the TipProvider file.

Plus, having it set up as a StreamProvider allows the data to be kept updated in real time! And there is virtually no extra cost in Firebase, as compared to calling it manually each time.

The end result is displaying that tip within the app like so, with real time updates to the likes count! Neat right!?

1
$ 5.84
$ 5.84 from @TheRandomRewarder
Avatar for nolyoi
Written by
3 years ago
Topics: Programming, Flutter, Dart, Code, Coding, ...

Comments