You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter运行报错LateInitializationError: Field 'Db'未初始化问题排查

报错原因
  • 核心原因是DbProvider的异步初始化逻辑没有等待完成就直接访问了late修饰的Db字段:DbProvider构造函数内调用的init()是异步方法,Dart中构造函数无法被标记为async,所以实例化DbProvider后代码会直接往下执行,此时init内的openDatabase异步操作还未执行完成,Db字段尚未被赋值,后续访问时就触发LateInitializationError。
  • 多处重复实例化DbProvider:Bloc类、NameTiles的build方法中各创建了一个独立的DbProvider实例,不仅重复初始化数据库造成资源浪费,也增大了初始化未完成就被访问的概率。
  • 数据库操作前无初始化校验:fetchInfoWithNameOrder等方法直接访问db.Db,没有任何逻辑判断数据库是否已经初始化完成。
  • 原代码存在SQL语法错误:Att表的建表语句中name text,后面多了一个多余的逗号,会导致onCreate执行失败,也会引发Db字段赋值失败。

修复方案

1. 将DbProvider改造为单例+异步安全获取实例

避免重复初始化,同时保证所有访问数据库的操作都等初始化完成后再执行,改造后代码如下:

import 'dart:async';
import 'package:path/path.dart';
import 'package:sqflite/sqflite.dart';
import 'package:path_provider/path_provider.dart';

class DbProvider{
  Database? _db;
  // 单例实现,全局仅一个实例
  static final DbProvider _instance = DbProvider._internal();
  factory DbProvider() => _instance;
  DbProvider._internal();

  Completer<void>? _initCompleter;

  Future<void> init() async {
    // 避免重复执行初始化逻辑
    if (_initCompleter != null) return _initCompleter!.future;
    _initCompleter = Completer<void>();
    try {
      Directory dir = await getApplicationDocumentsDirectory();
      final path = join(dir.path, 'AppDb.db');
      _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
            );
            """
          );
        }
      );
      _initCompleter!.complete();
    } catch (e) {
      _initCompleter!.completeError(e);
    }
    return _initCompleter!.future;
  }

  // 暴露安全的数据库实例获取方法
  Future<Database> get db async {
    if (_db == null) {
      await init();
    }
    return _db!;
  }
}

2. 修改Bloc中的数据库调用逻辑

所有访问数据库的位置先异步等待获取数据库实例:

fetchInfo(String arg) async{
  print('\nfetchInfo\n');
  // 等待数据库初始化完成后再获取实例
  final dbInstance = await db.db;
  var ans = await dbInstance.query(
    "Names",
    where: "name = ?",
    whereArgs: [arg],
  );
  print(ans);
  addToTile(ans);
}

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

3. 清理冗余代码

删除NameTiles类build方法中冗余的final db = DbProvider();实例化代码,全局统一使用Bloc中持有的单例即可。

可选优化

可在应用启动入口(如main函数中runApp之前)提前执行await DbProvider().init();预加载数据库,减少首次业务调用的等待耗时。


内容的提问来源于stack exchange,提问作者sharmaji saheb

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.08 04:48:03