Search code examples
firebaseflutterstreamiteratorprovider

The getter 'iterator' was called on null. Flutter & FireBase


i have a problem and dont know how to solve... I want to get data through a stream from Firebase i have UserData in FireBase and now want to get in another script by using a Stream of this UserData(Cutom Class) but the stream is throwing a error. I already proofed the basic lines, if i am using an iterator on null. But i think i dont. There has to be something wrong with the provider. Here is the error :

════════ Exception caught by provider ══════════════════════════════════════════════════════════════
The following assertion was thrown:
An exception was throw by _MapStream<DocumentSnapshot, UserData> listened by

StreamProvider<UserData>, but no `catchError` was provided.

Exception:
NoSuchMethodError: The getter 'iterator' was called on null.
Receiver: null
Tried calling: iterator

════════════════════════════════════════════════════════════════════════════════════════════════════

This is the basic stream:

  final String uid;
  DatabaseService({this.uid});
  final CollectionReference userCollection = Firestore.instance.collection("user");

Stream<UserData> get userData{
    if(userCollection.document(uid).snapshots() != null){
      return userCollection.document(uid).snapshots().map(_userDataFromSnapshot);
    }
    else{
      return null;
    }
  }

UserData _userDataFromSnapshot(DocumentSnapshot snapshot){
    List<Map<String, dynamic>> daysMaps = List<Map<String, dynamic>>.from(snapshot.data["days"]);
    List<Day> days = [];
    //List<dynamic> _daysMaps = snapshot.data["days"];
    if(daysMaps.length > 1){
      days = daysMaps.map((day) => Day.fromMap(day)).toList();
    }
    else{
      days.add(Day.fromMap(daysMaps[0]));
    }

    Map<String,dynamic> todayMap = Map<String,dynamic>.from(snapshot.data["today"]);
    Day today = Day.fromMap(todayMap);
    return UserData(
      uid: uid,
      name: snapshot.data["name"],
      days: days,
      today: today,
    );
  }

and this is where i make the StreamProvider (the user stream above is another one):

class Wrapper extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final user = Provider.of<User>(context);
    if(user == null){
      return Authenticate();
    }
    else{
      return StreamProvider<UserData>.value(
          value: DatabaseService(uid: user.uid).userData,
          child: Home()
      );
    }
  }
}

i dont know if in here is the error but this is the Home Widget:

class Home extends StatefulWidget {
  @override
  _HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
  int _currentIndex = 1;
  @override
  Widget build(BuildContext context) {
    //getting other streams
    final userdata = Provider.of<UserData>(context);
    final user = Provider.of<User>(context);
    print(userdata);
    final AuthService _auth = AuthService();
    //_auth.signOut();
    List<dynamic> tabs = [
      //TrainingTab
      Center(child: Text("Coming Soon")),
      //HomeTab
      Padding(
        padding: const EdgeInsets.all(10.0),
        child: Column(
          children: <Widget>[
            DayStats(),
            DayOverview(),
          ],
        ),
      ),
      //
      Center(child: FloatingActionButton(
          onPressed: (){
            DatabaseService(uid: user.uid).updateUserData([],  Day(
                burnedCalories: 300,
                targetCalories: 0,
                foodCalories: 0,
                date: DateTime(DateTime.now().year,DateTime.now().month,DateTime.now().day,0,0,0,0,0)));
          },
      ))
    ];
    return userdata != null ? Scaffold(
      backgroundColor: Color.fromRGBO(193, 214, 233, 1),
      appBar: AppBar(
        title: Text("MyApp"),
        centerTitle: true,
        elevation: 0.0,
        actions: <Widget>[
          FlatButton.icon(
              onPressed: () async {
                await _auth.signOut();
                Navigator.pushReplacementNamed(context, "/Wrapper");
              },
              icon: Icon(Icons.person),
              label: Text("logout")
          )
        ],
      ),
      body: tabs[_currentIndex],
      bottomNavigationBar: BottomNavigationBar(
        backgroundColor: Colors.white,
        currentIndex: _currentIndex,
        items: [
          BottomNavigationBarItem(
              icon: Icon(Icons.fitness_center),
              title: Text("Workout")
          ),
          BottomNavigationBarItem(
              icon: Icon(Icons.home),
              title: Text("Home")
          ),
          BottomNavigationBarItem(
              icon: Icon(Icons.fastfood),
              title: Text("Ernährung")
          )
        ],
        onTap: (index) {
          setState(() {
            _currentIndex = index;
          });
        },
      ),
    ) : Loading();
  }
}

Solution

  • I used List.from, without checking for null.