user10601874
user10601874

Reputation: 133

Stream.asFuture() duplicating data when widget is refreshed

When i first load the widget it gives me an error but works as expected. When I go to another screen then back though it will duplicated the data from the future.

@override
  Widget build(BuildContext context) {
   

    final userdata = context.watch<UserDataNotifier>();


    UserData data = Provider.of<UserData>(context);

    double h = MediaQuery.of(context).size.height;

    // print(data);
    return StreamBuilder(
      stream: Stream.fromFuture(data.getTheUserClasses),
      builder: (context, snapshot) {
        snapshot.data.toString();
        return Scaffold(
          backgroundColor: Color(0xff3DDC97),
          appBar: AppBar(
            backgroundColor: Color(0xff7211E0),
            title: userdata.user == null
                ? CircularProgressIndicator()
                : Text(userdata.user.firstName ?? ""),
          ),
          body: Container(
              // padding: EdgeInsets.symmetric(vertical: h / 8),
              padding: EdgeInsets.fromLTRB(0, h / 8, 0, 0),
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                mainAxisSize: MainAxisSize.min,
                children: <Widget>[
                  SizedBox(
                      height: h * .5,
                      child: data.classList == null
                          ? Loading()
                          : data.classList.isEmpty
                              ? Loading()
                              : UserClassList(
                                  data: data.classList,
                                )),
                  RaisedButton(
                    child: Text("Add Class"),
                    onPressed: () {
                      Navigator.push(
                              context,
                              MaterialPageRoute(
                                  builder: (context) => PickFromAllClasses()))
                          .then((value) => value ? _refresh() : null);
                    },
                    shape: RoundedRectangleBorder(
                        borderRadius: BorderRadius.circular(20)),
                    color: Colors.blue,
                  )
                ],
              )),
        );
      },
    );
  }

here is how I get the data

    class UserData {
  String uid;
  String firstName;
  int rating;
  List<String> classes;
  List<ClassData> classList = List<ClassData>();

  UserData.fromMap(Map<String, dynamic> data) {
    firstName = data['firstname'] ?? "";
    rating = data['rating'] ?? "";
    classes = data['classes'].cast<String>() ?? "";
  }

 

  List<ClassData> get cs => classList;

  set cs(List<ClassData> s) {
    cs = s;
  }

  Future get getTheUserClasses async {
    for (String c in classes) {
      DocumentSnapshot classsnapshot =
          await Firestore.instance.collection("Classes").document(c).get();

      final data =
          ClassData.fromUserMap(classsnapshot.data, classsnapshot.documentID);

      if (data != null) {
        classList.add(data);
        // print(data.classdescription);
      }
    }

    cs = classList;
  }

  UserData({this.firstName, this.rating, this.classes});
}

Here is the error I get when I load this widget.

flutter: ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
flutter: The following NoSuchMethodError was thrown building YourClasses(dirty, dependencies: [MediaQuery,
flutter: _InheritedProviderScope<UserDataNotifier>, _InheritedProviderScope<UserData>], state:
flutter: _YourClassesState#4bf6d):
flutter: The getter 'getTheUserClasses' was called on null.
flutter: Receiver: null
flutter: Tried calling: getTheUserClasses
flutter:
flutter: The relevant error-causing widget was:
flutter:   YourClasses
flutter:   file:///Users/devintripp/Desktop/flutter_apps.no_sync/discoverytutors/lib/Screens/LoggedIn/TutorsView/tutors.dart:148:65
flutter:
flutter: When the exception was thrown, this was the stack:
flutter: #0      Object.noSuchMethod (dart:core-patch/object_patch.dart:53:5)
flutter: #1      _YourClassesState.build (package:disc_t/Screens/LoggedIn/Classes/yourclasses.dart:66:38)
flutter: #2      StatefulElement.build (package:flutter/src/widgets/framework.dart:4619:28)
flutter: #3      ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4502:15)
flutter: #4      StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:4675:11)
flutter: #5      Element.rebuild (package:flutter/src/widgets/framework.dart:4218:5)
flutter: #6      ComponentElement._firstBuild (package:flutter/src/widgets/framework.dart:4481:5)
flutter: #7      StatefulElement._firstBuild (package:flutter/src/widgets/framework.dart:4666:11)
flutter: #8      ComponentElement.mount (package:flutter/src/widgets/framework.dart:4476:5)
flutter: ...     Normal element mounting (24 frames)
flutter: #32     Element.inflateWidget (package:flutter/src/widgets/framework.dart:3446:14)
flutter: #33     MultiChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:5947:32)
flutter: ...     Normal element mounting (119 frames)
flutter: #152    Element.inflateWidget (package:flutter/src/widgets/framework.dart:3446:14)
flutter: #153    Element.updateChild (package:flutter/src/widgets/framework.dart:3214:18)
flutter: #154    RenderObjectElement.updateChildren (package:flutter/src/widgets/framework.dart:5580:32)
flutter: #155    MultiChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:5957:17)
flutter: #156    Element.updateChild (package:flutter/src/widgets/framework.dart:3201:15)
flutter: #157    ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4527:16)
flutter: #158    StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:4675:11)
flutter: #159    Element.rebuild (package:flutter/src/widgets/framework.dart:4218:5)
flutter: #160    StatefulElement.update (package:flutter/src/widgets/framework.dart:4707:5)
flutter: #161    Element.updateChild (package:flutter/src/widgets/framework.dart:3201:15)
flutter: #162    ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4527:16)
flutter: #163    Element.rebuild (package:flutter/src/widgets/framework.dart:4218:5)
flutter: #164    ProxyElement.update (package:flutter/src/widgets/framework.dart:4862:5)
flutter: #165    _InheritedNotifierElement.update (package:flutter/src/widgets/inherited_notifier.dart:181:11)
flutter: #166    Element.updateChild (package:flutter/src/widgets/framework.dart:3201:15)
flutter: #167    SingleChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:5837:14)
flutter: #168    Element.updateChild (package:flutter/src/widgets/framework.dart:3201:15)
flutter: #169    ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4527:16)
flutter: #170    StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:4675:11)
flutter: #171    Element.rebuild (package:flutter/src/widgets/framework.dart:4218:5)
flutter: #172    StatefulElement.update (package:flutter/src/widgets/framework.dart:4707:5)
flutter: #173    Element.updateChild (package:flutter/src/widgets/framework.dart:3201:15)
flutter: #174    SingleChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:5837:14)
flutter: #175    Element.updateChild (package:flutter/src/widgets/framework.dart:3201:15)
flutter: #176    SingleChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:5837:14)
flutter: #177    Element.updateChild (package:flutter/src/widgets/framework.dart:3201:15)
flutter: #178    ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4527:16)
flutter: #179    Element.rebuild (package:flutter/src/widgets/framework.dart:4218:5)
flutter: #180    StatelessElement.update (package:flutter/src/widgets/framework.dart:4583:5)
flutter: #181    Element.updateChild (package:flutter/src/widgets/framework.dart:3201:15)
flutter: #182    ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4527:16)
flutter: #183    StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:4675:11)
flutter: #184    Element.rebuild (package:flutter/src/widgets/framework.dart:4218:5)
flutter: #185    BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2627:33)
flutter: #186    WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:883:20)
flutter: #187    RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:284:5)
flutter: #188    SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1113:15)
flutter: #189    SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1052:9)
flutter: #190    SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:968:5)
flutter: #194    _invoke (dart:ui/hooks.dart:261:10)
flutter: #195    _drawFrame (dart:ui/hooks.dart:219:3)
flutter: (elided 3 frames from dart:async)

Here is the screen that is loaded at first.

enter image description here

then when it duplicates it gets the same data 3 times. This is after i refresh this widget.

enter image description here

Upvotes: 1

Views: 490

Answers (2)

Luca
Luca

Reputation: 44

Stream.fromFuture() does not cover your use case. It will not update if new elements are added or elements are deleted (since it just gets the elements from a Future).

In your case you might want to do something like the following:

Stream<List<YourModel>> getUserList() {
return Firestore.instance.collection('Classes')
    .snapshots()
    .map((snapShot) => snapShot.documents
    .map((document) => Yourmodel.fromDocument(document.data)
    .toList());
}

Furthermore, in order to avoid the error you see in the console, you need to check whether the document has data (e.g. if (document.hasData())) and return the widget to be displayed if no data is available yet.

Upvotes: 1

nvoigt
nvoigt

Reputation: 77295

Instead of using a StreamBuilder, use a FutureBuilder.

Instead of creating your Future on every build, create the Future once and save it to a variable in your state, so it does not get called again and again, but only once, no matter how many times your build method is called.

Upvotes: 1

Related Questions