Flutter:解决SharedPreferences填充StatefulWidget列表的Future错误及SQLite问题
问题解决方案
一、修复Future调用split的报错问题
错误核心原因:getDBNames()是异步函数,返回的是Future<List<String>>类型对象,你直接对Future实例调用split方法,而Future本身并没有这个方法,因此触发报错。以下是两种可行的修复方案:
方案1:通过异步方法更新状态
修改_ListCardState代码,将异步数据获取逻辑抽离为单独方法,在initState中调用,获取数据后通过setState更新UI:
class _ListCardState extends State<ListCard> { List<String> _dbList = []; // 初始化空列表,避免late关键字的潜在风险 @override void initState() { super.initState(); _loadDatabaseNames(); } // 异步加载SharedPreferences中的文件名列表 Future<void> _loadDatabaseNames() async { final names = await getDBNames(); setState(() { _dbList = names; }); } @override Widget build(BuildContext context) { return ListView.builder( itemCount: _dbList.length, itemBuilder: (BuildContext context, int index) { return Card( shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)), child: Padding( padding: const EdgeInsets.all(12.0), child: Text(_dbList[index]), ), ); }, ); } }
同时优化getDBNames函数,明确返回类型并处理空字符串边界情况:
Future<List<String>> getDBNames() async { SharedPreferences prefs = await SharedPreferences.getInstance(); String dbNames = prefs.getString('dbNames') ?? ''; // 避免空字符串split后生成包含空元素的列表 return dbNames.isEmpty ? [] : dbNames.split(','); }
方案2:使用FutureBuilder处理异步数据
这种方案无需手动管理状态,直接用FutureBuilder包裹ListView,简化异步数据的UI渲染逻辑:
class _ListCardState extends State<ListCard> { @override Widget build(BuildContext context) { return FutureBuilder<List<String>>( future: getDBNames(), initialData: [], // 初始状态显示空列表 builder: (context, snapshot) { // 加载中显示进度指示器 if (snapshot.connectionState == ConnectionState.waiting) { return const Center(child: CircularProgressIndicator()); } final dbList = snapshot.data ?? []; return ListView.builder( itemCount: dbList.length, itemBuilder: (BuildContext context, int index) { return Card( shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)), child: Padding( padding: const EdgeInsets.all(12.0), child: Text(dbList[index]), ), ); }, ); }, ); } }
getDBNames函数的优化同方案1。
二、启动时读取SQLite数据库列表并显示
可以通过获取SQLite默认存储目录,遍历目录下的.db文件来获取数据库列表,具体步骤如下:
- 添加依赖:在
pubspec.yaml中添加路径获取和SQLite相关依赖
dependencies: path_provider: ^2.1.1 sqflite: ^2.3.2 path: ^1.8.3 # 用于处理文件路径
- 编写获取SQLite数据库列表的异步函数
import 'dart:io'; import 'package:path_provider/path_provider.dart'; import 'package:path/path.dart'; Future<List<String>> getSQLiteDBList() async { // 获取应用文档目录(SQLite默认存储路径) Directory appDocDir = await getApplicationDocumentsDirectory(); List<String> dbNames = []; // 遍历目录下的所有文件,筛选出.db后缀的文件 List<FileSystemEntity> files = appDocDir.listSync(); for (var file in files) { if (file is File && file.path.endsWith('.db')) { // 提取不带路径和后缀的纯文件名 String fileName = basenameWithoutExtension(file.path); dbNames.add(fileName); } } return dbNames; }
- 在ListView中使用该函数
用法与修复SharedPreferences的方案一致,例如用FutureBuilder:
class _ListCardState extends State<ListCard> { @override Widget build(BuildContext context) { return FutureBuilder<List<String>>( future: getSQLiteDBList(), initialData: [], builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { return const Center(child: CircularProgressIndicator()); } final dbList = snapshot.data ?? []; return ListView.builder( itemCount: dbList.length, itemBuilder: (BuildContext context, int index) { return Card( shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)), child: Padding( padding: const EdgeInsets.all(12.0), child: Text(dbList[index]), ), ); }, ); }, ); } }
内容的提问来源于stack exchange,提问作者AashishKSahu
相关产品推荐
相关产品推荐

