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

Flutter SQFLite如何查询列值并在UI中展示

如何在Flutter UI中展示SQFLite数据库中的数据

要在UI中展示SQFLite里的数据,核心是异步获取数据库数据并与UI组件绑定,这里推荐用FutureBuilder处理异步数据的加载、展示和异常情况。以下是基于你提供代码的完整修改方案:

关键修改点

  • 修复数据库操作的异步调用逻辑:addItem和removeItem需等待数据库操作完成后再更新UI状态
  • 使用FutureBuilder包裹数据展示组件,处理数据库查询的异步过程
  • 添加列表组件展示所有数据库中的数据

修改后的完整代码

import 'package:flutter/material.dart';
import 'package:path/path.dart';
import 'package:sqflite/sqflite.dart';

void main() {runApp(const MyApp());}

class MyApp extends StatefulWidget {
  const MyApp({super.key});

  @override
  MyAppState createState() => MyAppState();
}

class DataFields {
  static final List<String> values = [id, name];
  static final String id = '_id';
  static final String name = 'myName';
}

class DataModel{
  int id;
  String name;
  DataModel({required this.id, required this.name});

  DataModel copy({int? id,String? title,String? description,int? isSelected}) => 
      DataModel(id: id ?? this.id,name: name ?? this.name);
  
  Map<String, Object?> toJson() => {
    if (id != null) DataFields.id: id,
    DataFields.name: name
  };
  
  static DataModel fromJson(Map<String, Object?> json) => 
      DataModel(
        id: json[DataFields.id] as int,
        name: json[DataFields.name] as String
      );
 }


class DBHelper {
  final String myTable = 'myDataTable';
  static const String myDatabase = 'myDB.db';

  DBHelper._init();
  static final DBHelper instance = DBHelper._init();
  static Database? _database;

  Future<Database> get dataBase async {
    if (_database != null) {
      return _database!;
    } else {
      _database = await _initDB(myDatabase);
      return _database!;
    }
  }

  Future<Database> _initDB(String filePath) async {
    final dbPath = await getDatabasesPath();
    final path = join(dbPath, filePath);
    return await openDatabase(path, version: 1, onCreate: _createDB);
  }

  Future _createDB(Database db, int version) async {
    var idType = 'INTEGER PRIMARY KEY AUTOINCREMENT';
    var textType = 'TEXT NOT NULL';
    await db.execute('''
      CREATE TABLE $myTable (
        ${DataFields.id} $idType,
        ${DataFields.name} $textType
      )
    ''');
  }

  Future<DataModel> create(DataModel datamodel) async {
    final db = await instance.dataBase;
    final id = await db.insert(myTable, datamodel.toJson());
    return datamodel.copy(id: id);
  }

  Future<DataModel> readData(int id) async {
    final db = await instance.dataBase;
    final maps = await db.query(
      myTable,
      columns: DataFields.values,
      where: '${DataFields.id} = ?',
      whereArgs: [id]
    );
    if (maps.isNotEmpty) {
      return DataModel.fromJson(maps.first);
    } else {
      throw Exception('ID $id not found');
    }
  }

  Future<List<DataModel>> readAllData() async {
    final db = await instance.dataBase;
    final result = await db.rawQuery('SELECT * FROM $myTable');
    return result.map((json) => DataModel.fromJson(json)).toList();
  }

  Future<int> countAllDataRows() async {
    final db = await instance.dataBase;
    var x = await db.rawQuery('SELECT COUNT(1) FROM $myTable');
    return Sqflite.firstIntValue(x) ?? 0;
  }

  Future<int> update(DataModel datamodel) async {
    final db = await instance.dataBase;
    return db.update(
      myTable,
      datamodel.toJson(),
      where: '${DataFields.id} = ?',
      whereArgs: [datamodel.id]
    );
  }

  Future<int> delete(int id) async {
    final db = await instance.dataBase;
    return await db.delete(
      myTable,
      where: '${DataFields.id} = ?',
      whereArgs: [id]
    );
  }

  Future close() async {
    final db = await instance.dataBase;
    db.close();
  }
}

class MyAppState extends State<MyApp> {
  final TextEditingController mc = TextEditingController();
  int index = 0;

  // 修复异步操作,等待数据库完成后更新状态
  Future<void> addItem() async {
    if (mc.text.isNotEmpty) {
      await DBHelper.instance.create(DataModel(id:index,name:mc.text));
      setState(() {
        index++;
        mc.clear();
      });
    }
  }

  // 修复异步操作,等待数据库完成后更新状态
  Future<void> removeItem() async {
    if (index >0){
      await DBHelper.instance.delete(index);
      setState(() {
        index--;
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    Widget space = const SizedBox(height: 15);
    Widget myinput = TextField(
      controller: mc,
      decoration: const InputDecoration(
        border: OutlineInputBorder(), 
        labelText: 'Name'
      ),
    );
    Widget btnAdd = ElevatedButton(onPressed: addItem, child: const Text('Add'));
    Widget btnRemove = ElevatedButton(onPressed: removeItem, child: const Text('Remove'));

    // 用FutureBuilder异步获取并展示数据
    Widget dataList = FutureBuilder<List<DataModel>>(
      future: DBHelper.instance.readAllData(),
      builder: (context, snapshot) {
        if (snapshot.connectionState == ConnectionState.waiting) {
          return const CircularProgressIndicator();
        } else if (snapshot.hasError) {
          return Text('加载失败: ${snapshot.error}');
        } else if (!snapshot.hasData || snapshot.data!.isEmpty) {
          return const Text('暂无数据');
        } else {
          return ListView.builder(
            shrinkWrap: true,
            physics: const NeverScrollableScrollPhysics(),
            itemCount: snapshot.data!.length,
            itemBuilder: (context, index) {
              final item = snapshot.data![index];
              return ListTile(
                title: Text(item.name),
                subtitle: Text('ID: ${item.id}'),
              );
            },
          );
        }
      },
    );

    return MaterialApp(
      home: Scaffold(
        resizeToAvoidBottomInset: false,
        appBar: AppBar(title: const Text('数据库数据展示')),
        body: SingleChildScrollView(
          padding: const EdgeInsets.all(16),
          child: Column(
            mainAxisSize: MainAxisSize.min,
            children: <Widget>[
              myinput,
              space,
              Row(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [btnAdd, const SizedBox(width: 20), btnRemove],
              ),
              space,
              const Divider(height: 2, color: Colors.grey),
              space,
              const Text('数据库中的数据:', style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold)),
              space,
              dataList,
            ],
          ),
        ),
      ),
    );
  }
}

核心逻辑说明

  1. 异步操作修复:addItem和removeItem改为Future<void>,用await等待数据库操作完成后再调用setState,确保数据与UI状态同步。
  2. FutureBuilder的作用:
    • 传入readAllData()作为异步数据源,自动处理加载状态
    • 分别处理加载中(显示进度条)、加载失败(显示错误信息)、无数据(提示文本)、有数据(展示列表)四种场景
  3. 列表渲染:使用ListView.builder遍历数据库返回的列表数据,shrinkWrap: true和NeverScrollableScrollPhysics确保列表适配父滚动容器。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 03:27:02