Search code examples
flutterstatefulwidget

Flutter - The method '|' was called on null. After hot reload it is working


I am pretty new in flutter. I don't know what happening in background because after hot reload its work fine. On another dart files that happens, firebase dont provide me data on initialization just after hot reload.

class CityServices {
      getCites() {
        return Firestore.instance.collection('cities').getDocuments();
      }
    }

class _HomeScreenState extends State<HomeScreen> {
  bool citiesFlag = false;
  var cities;
  int citiesCount;
  String actualCity;

Maybe mistake is here.

  @override
  void initState() {
    super.initState();
    CityServices().getCites().then((QuerySnapshot) {
      if (QuerySnapshot.documents.isNotEmpty) {
        citiesFlag = true;
        cities = QuerySnapshot.documents;
        citiesCount = QuerySnapshot.documents.length;
      }
    });
  }


  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: Scaffold(
        backgroundColor: MyColors.vintageGreen,
        appBar: AppBar(
          backgroundColor: MyColors.background,
          title: Center(
            child: Text(
              'Válasszon települést...',
              style: GoogleFonts.barlowCondensed(
                  color: MyColors.appbarText,
                  fontSize: 26.0,
                  fontWeight: FontWeight.w500),
            ),
          ),
        ),
        body: Center(
          child: Container(
            child: GridView.count(
              crossAxisCount: 2,
              children: List.generate(citiesCount, (index) {
                return Card(
                  shape: RoundedRectangleBorder(
                    borderRadius: BorderRadius.all(Radius.circular(10)),
                  ),
                  child: InkWell(
                    onTap: () {
                      actualCity = cities[index]['city_name'];
                      Navigator.push(
                        context,
                        MaterialPageRoute(
                            builder: (context) =>
                                CityView(cityName: actualCity)),
                      );
                    },
                    child: Column(
                      mainAxisSize: MainAxisSize.min,
                      children: <Widget>[
                        ListTile(
                          title: Center(
                              child: Text(
                            cities[index]['city_name'],
                            style: TextStyle(
                                fontWeight: FontWeight.w500, fontSize: 18.0),
                          )),
                          subtitle: Center(child: Text('22 bejegyzés')),
                        ),
                        Flexible(
                          child: ClipRRect(
                            borderRadius: BorderRadius.all(Radius.circular(5)),
                            child: Padding(
                              padding: EdgeInsets.only(bottom: 15.0),
                              child: Image(
                                image: AssetImage(
                                  cities[index]['img_path'],
                                ),
                              ),
                            ),
                          ),
                        )
                      ],
                    ),
                  ),
                  color: MyColors.background,
                );
              }),
            ),
          ),
        ),
      ),
    );
  }
}

Maybe here is the mistake? Should it be on top of dart file?

class HomeScreen extends StatefulWidget {
  static const String id = 'home';
  @override
  _HomeScreenState createState() => new _HomeScreenState();
}

Solution

  • Let me explain the issue and why it is happening, then propose few solutions.

    inside initState you are calling CityServices().getCites().then... which is an async method.
    However, when your widget is built for the first time, the data you expect from Firestore is not ready yet, thus you get null for both cities and citiesCount.

    Short term solution:
    make sure there is null check, display indicator while waiting for the data.

    body: Center(
       child: (cities == null) ? 
         CircularProgressIndicator()
         : Container(...
    

    Additionally, you can also refactor your initState to something like this

    void getCities() async {
       var snapshot CityServices().getCites();
       setState(() {
            citiesFlag = true;
            cities = snapshot.documents;
            citiesCount = snapshot.documents.length;
          });
    }
    
    @override
      void initState() {
        getCities();  
        super.initState();
      }
    

    Long term solution:
    use BLoC pattern and make data loading decoupled from UI.
    see flutter_bloc for how to implement it.