21

I am fetching data from url in Flutter. I have a late init Map called tables. I am fetching data inside initState() function. When I first launch the app, I am getting LateInizialization error on the red screen. I want to detect whether late init is initialized and display spinner if it is not initialized. This is my code.

class TablesTab extends StatefulWidget {
  @override
  _TablesTabState createState() => _TablesTabState();
}

class _TablesTabState extends State<TablesTab> {
  late List<dynamic> tables;
  var refreshKey = GlobalKey<RefreshIndicatorState>();
  GetUriData tablesInstance = new GetUriData(url: '/api/table/getAllTables');

  void getTables() async {
    tables = await tablesInstance.getData();
  }

  @override
  void initState() {
    super.initState();
    getTables();
  }

  Future<void> refreshList() async {
    refreshKey.currentState?.show(atTop: false);
    // await Future.delayed(Duration(seconds: 2));
    var updatedTables = await tablesInstance.getData();
    setState(() {
      tables = updatedTables;
    });

    //network call and setState so that view will render the new values
    print(tables);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: RefreshIndicator(
          child:  GridView.count(
            crossAxisCount: 4,
            children: List.generate(this.tables.length, (index) {
              return Center(
                child: GestureDetector(
                  onTap: () {
                    Navigator.pushNamed(context, '/tableReview', arguments: {'table': this.tables[index]});
                  },
                  child: Container(
                      width: 80,
                      height: 80,
                      decoration: BoxDecoration(
                          border: Border.all(color: Theme.of(context).primaryColor, width: 2.0),
                          borderRadius: BorderRadius.all(Radius.circular(70))
                      ),
                      padding: const EdgeInsets.all(14.0),
                      child: Column(
                        mainAxisAlignment: MainAxisAlignment.center,
                        crossAxisAlignment: CrossAxisAlignment.center,
                        children: [
                          Text(
                            '${this.tables[index]['tableNum']}',
                            style: TextStyle(
                                color: Theme.of(context).primaryColor,
                                fontSize: 23
                            ),
                          ),
                        ],
                      )
                  ),
                ),
              );
            }),
          ),
          onRefresh: refreshList
      )
    );
  }
Sardorek Aminjonov
  • 724
  • 2
  • 7
  • 16

5 Answers5

12

You can't know whether late field initialized or not.

I don't think you should use late in that case. Adding late to field means that the field will be initialized when you use it for the first time. In your code the field can be not initialized, so you'd better to use tables without late, initialize it with empty list and use boolean flag to indicate loading:

  var tables = [];
  var loading = false;

  ...

  Future<void> refreshList() async {
    ...
    setState(() {
      loading = true;
    });
    var updatedTables = await tablesInstance.getData();
    setState(() {
      tables = updatedTables;
      loading = false;
    });
    ...
  }
Mol0ko
  • 2,938
  • 1
  • 18
  • 45
7

You can't check the initialization state of a late variable. If that's something you need to know, you either will need to add and maintain a separate flag or make the variable nullable and compare to null instead.

I want to detect whether late init is initialized and display spinner if it is not initialized.

In your case you probably should use a FutureBuilder.

jamesdlin
  • 81,374
  • 13
  • 159
  • 204
  • Thnx. But when am I supposed to use late init then? – Sardorek Aminjonov Mar 24 '21 at 08:10
  • 2
    You'd use `late` when you can logically *guarantee* that the variable won't be used before it's initialized. One example would be a member that must be initialized within the constructor body (and can't be initialized from the initializer list). – jamesdlin Mar 24 '21 at 09:42
0

I think I found the answer, in my case, it is not about the mapController, it is about size I added Flexible as parent of FlutterMap and map showing perfect

Try below code:

Flexible(
  child: FlutterMap(
    options: MapOptions(
      center: LatLng(51.5, -0.09),
      zoom: 5.0,
    ),
    layers: [
      TileLayerOptions(
        urlTemplate:
            'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
        subdomains: ['a', 'b', 'c'],
        tileProvider:
            NonCachingNetworkTileProvider(),
      ),
      MarkerLayerOptions(markers: [])
    ],
  ),
),
Guvanch
  • 838
  • 7
  • 10
0

You can give any default value in the constructor if you are using late initializer or you can make them nullable but making nullable is hectic

0

You can.

class MyClass {
  late double myLateField;
  bool _isInitialized = false;

  void myFunction() {
    if (!_isInitialized) {
      _isInitialized = true;
      // ... init your late field.
    }
  }

}

As others have said, you probably shouldn't do this. But technically, it's possible with this workaround.

Bobin
  • 278
  • 5
  • 15