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

Flutter使用sqflite查询SQLite赋值列表为空调用length报错如何解决

问题根因

你遇到的报错本质是异步方法执行时序问题:

  • query()是异步方法,调用后不会等待数据库查询完成就会直接执行后续的assert和convert()方法,此时listLokasi还没被赋值,自然为null。
  • 构造函数不支持async/await,没法等待异步操作完成再执行后续逻辑。
  • 另外你还有两个隐藏问题:数据库实例没有主动初始化、BLOB转File的方法使用错误。

修复步骤

1. 调整初始化逻辑

将异步初始化逻辑移到State的initState生命周期方法中执行,查询、转换完成后调用setState更新页面状态:

class _DataPageState extends State<DataPage> {
  DatabaseHelper db = DatabaseHelper();
  List<Lokasi> listLokasi = [];
  List<LokasiConvert> listLokasiConvert = [];
  // 增加loading状态控制
  bool isLoading = true;

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

  Future<void> initData() async {
    // 先初始化数据库,必须调用否则db实例为null
    await db.initDatabase();
    await query();
    await convert();
    if (mounted) {
      setState(() {
        isLoading = false;
      });
    }
  }
  // 其余原有方法保持
}

2. 修复BLOB转File逻辑

File.fromRawPath是把传入的字节当做文件路径解析,不能直接用来把图片字节转成File,需要先把BLOB返回的Uint8List写入本地临时文件再生成File对象。
需要先在pubspec.yaml中引入官方路径工具包:

dependencies:
  flutter:
    sdk: flutter
  path_provider: ^2.1.0

然后修改convert方法:

Future<void> convert() async {
  final tempDir = await getTemporaryDirectory();
  listLokasiConvert = List.generate(
    listLokasi.length,
    (i) {
      // 生成临时文件
      final tempFile = File('${tempDir.path}/${listLokasi[i].id}.png');
      tempFile.writeAsBytesSync(listLokasi[i].image);
      return LokasiConvert(
        name: listLokasi[i].name,
        description: listLokasi[i].description, // 你原有代码这里写错成category了
        category: listLokasi[i].category,
        latitude: listLokasi[i].latitude,
        longitude: listLokasi[i].longitude,
        image: tempFile,
      );
    },
  );
}

3. 页面增加loading状态处理

build方法里先判断加载状态,避免列表未初始化时报错:

@override
Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(
      automaticallyImplyLeading: false,
      title: Text('Data'),
      actions: [
        RaisedButton(
          child: Text('Logout'),
          onPressed: () {
            Navigator.popUntil(context, ModalRoute.withName('/'));
          },
        ),
        RaisedButton(
          child: Text('Main'),
          onPressed: () {
            sendUsername(context);
          },
        ),
        RaisedButton(
          child: Text('Charts'),
          onPressed: () {
            sendUsernameToChart(context);
          },
        ),
      ],
    ),
    body: isLoading 
      ? const Center(child: CircularProgressIndicator())
      : ListView.builder(
        itemBuilder: (context, i) {
          return Card(
            child: Row(
              children: [
                Image.file(
                  listLokasiConvert[i].image,
                  width: 100,
                  height: 100,
                  fit: BoxFit.cover,
                ),
                Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text(listLokasiConvert[i].name),
                    Text(listLokasiConvert[i].category),
                    Text(listLokasiConvert[i].description),
                    Text('Coordinates: ${listLokasiConvert[i].latitude}, ${listLokasiConvert[i].longitude}'),
                  ],
                )
              ],
            ),
          );
        },
        itemCount: listLokasiConvert.length,
      ),
  );
}

4. 可选优化:DatabaseHelper单例初始化优化

避免重复调用initDatabase,可以把数据库实例改成懒加载:

class DatabaseHelper {
  static final _instance = DatabaseHelper._internal();
  DatabaseHelper._internal();
  factory DatabaseHelper() => _instance;

  Database? _db;

  Future<Database> get db async {
    if (_db != null) return _db!;
    _db = await _initDatabase();
    return _db!;
  }

  Future<Database> _initDatabase() async {
    var databasePath = await getDatabasesPath();
    var path = join(databasePath, 'table.db');
    return await openDatabase(path, version: 1, onCreate: onCreate);
  }

  Future<void> onCreate(Database db, int version) async {
    await db.execute('''
    CREATE TABLE lokasi 
    (id INTEGER PRIMARY KEY, 
    name TEXT, 
    description TEXT, 
    category TEXT, 
    latitude REAL, 
    longitude REAL, 
    image BLOB)
    ''');
  }

  Future<Lokasi> insert(Lokasi lokasi) async {
    final dbClient = await db;
    await dbClient.insert('lokasi', lokasi.toJson());
    return lokasi;
  }

  Future<List<Lokasi>> query() async {
    final dbClient = await db;
    var list = await dbClient.query('lokasi');
    return List.generate(list.length, (i) => Lokasi.fromJson(list[i]));
  }
}

调整后不需要主动调用initDatabase,直接调用db.query即可自动完成初始化。

内容的提问来源于stack exchange,提问作者Ignas Prasetyo

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 14:15:06