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, ], ), ), ), ); } }
核心逻辑说明
- 异步操作修复:
addItem和removeItem改为Future<void>,用await等待数据库操作完成后再调用setState,确保数据与UI状态同步。 - FutureBuilder的作用:
- 传入
readAllData()作为异步数据源,自动处理加载状态 - 分别处理加载中(显示进度条)、加载失败(显示错误信息)、无数据(提示文本)、有数据(展示列表)四种场景
- 传入
- 列表渲染:使用
ListView.builder遍历数据库返回的列表数据,shrinkWrap: true和NeverScrollableScrollPhysics确保列表适配父滚动容器。
内容的提问来源于stack exchange,提问作者DktPhl2018
相关产品推荐
相关产品推荐

