0

i am using this DbProvider class in many other files. it throws error:

[ERROR:flutter/lib/ui/ui_dart_state.cc(199)] Unhandled Exception: LateInitializationError: Field 'Db' has not been initialized.

E/flutter (12867): #0 DbProvider.Db (package:sample/src/Db.dart)

E/flutter (12867): #1 Bloc.fetchInfoWithNameOrder (package:sample/src/bloc.dart:31:24)

E/flutter (12867): #2 NameTiles.build. (package:sample/src/NameTiles.dart:20:16)

E/flutter (12867): #3 StreamBuilder.build (package:flutter/src/widgets/async.dart:546:81)

This is DbProvider class

class DbProvider{
  late Database Db;
  DbProvider(){init();}
  
  init()async{
    print("sdsdfaf");
    Directory dir = await getApplicationDocumentsDirectory();
    final path = join(dir.path, 'AppDb.db');
    print(dir.path);
    Db = await openDatabase(
      path,
      version: 1,
      onCreate: (Database newDb, int version){
        newDb.execute(
          """
          create table Names(
            id integer primary key,
            name text,
            Salary integer,
            total integer
          );

          create table Att(
            id integer primary key,
            name text,
          );
          """
        );
      }
    );

    print('\n\n\ndb init\n\n\n');
  }
}

This is bloc.dart file

class Bloc{
  final db = DbProvider();
  final _text_field_subject = BehaviorSubject();
  final _tile = BehaviorSubject();
  
  Function(String?) get addToTextSubject => _text_field_subject.sink.add;
  Stream get text_field_subject => _text_field_subject.stream;
  get text_field_subject_value => _text_field_subject.value;

  Function get addToTile => _tile.sink.add;
  Stream get tile => _tile.stream;

  fetchInfo(String arg) async{
    print('\nfetchInfo\n');
    var ans = await db.Db.query(
      "Names",
      where: "name = ?",
      whereArgs: [arg],
    );
    print(ans);
    addToTile(ans);
  }

  fetchInfoWithNameOrder()async{
    print('\nfetchinfowithorder\n');
    var ans = await db.Db.query(
      "Names",
      orderBy: "name asc",
    );
    print(ans);
    addToTile(ans);
  }
}

and here is the NameTiles class with builder:

class NameTiles extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    print('\n\n\n1\n\n\n');
    final db = DbProvider();
    print('\n\n\n3\n\n\n');
    final bloc = StreamProvider.of(context);
    return StreamBuilder(
      stream: bloc.tile,
      builder: (context, AsyncSnapshot? snapshot){
        print('\n\n\nre\n\n\n');  
        if(snapshot == null || !snapshot.hasData){
          print('\n\n\nStarting\n\n\n');
          bloc.fetchInfoWithNameOrder();
          return Text('loading');
        }
        print('\n\n\ntween\n\n\n');
        return Text('llll');
      },
    );
    
  }

  Widget tiles(info){
    return Container(
      height: 40,
      padding: EdgeInsets.all(5),
      clipBehavior: Clip.none,
      child: Row(children: [
        Text('${info.name}'),
        Text('${info.total}'),
      ],),
    );
  }
}

1 Answers1

0

You call init in your constructor, but you never wait for it to finish.

So your constructor runs, it trigers the init method, and while that runs, since it's async and has no await to wait for it, your program continues, finally coming to a part where your variable is needed, but not initialized yet, since init is still running.

Some tips:

  1. crank up warnings to a maximum, maybe using a package like pedantic
  2. actually provide return types for your async methods
  3. move your construction of DbProvider out of your build method
  4. instead of having a constructor, create a factory method and make it async, remember to provide a proper return type and call it with an await.

You may want to read up on What is a Future and how do I use it?

nvoigt
  • 75,013
  • 26
  • 93
  • 142