Flutter用分组ListView展示SharedPreferences数据时出现实例方法错误
解决Flutter中GroupedListView展示Bookmark数据的"[]方法不存在"错误
我尝试在分组ListView中展示存储在SharedPreferences的书签数据时,遇到以下错误:
Class 'Bookmark' has no instance method '[]'.
Receiver: Instance of 'Bookmark'
Tried calling:
书签数据格式(从SharedPreferences获取):
[{"surah_no":2,"verse_no":2,"surah_name":"Al-Baqarah","favorite":true}, {"surah_no":2,"verse_no":1,"surah_name":"Al-Baqarah","favorite":true}, {"surah_no":2,"verse_no":2,"surah_name":"Al-Baqarah","favorite":true}, {"surah_no":2,"verse_no":3,"surah_name":"Al-Baqarah","favorite":true}, {"surah_no":4,"verse_no":1,"surah_name":"An-Nisa'","favorite":true}, {"surah_no":8,"verse_no":1,"surah_name":"Al-Anfal","favorite":true}, {"surah_no":6,"verse_no":1,"surah_name":"Al-'An'am","favorite":true},...]
错误原因
- 数据解析失效:
_loadData方法仅将SharedPreferences中的字符串直接存入列表,随后创建空的Bookmark对象,未将JSON字符串解析为带有效属性的Bookmark实例,导致所有对象属性为null。 - 属性访问方式错误:GroupedListView的
groupBy、itemComparator和itemBuilder中,使用了element['surah_name']这种Map的键值访问方式,但element是Bookmark类实例,需用点语法访问属性。
修正后的完整代码
class Bookmark { final int surah_no, verse_no; final String surah_name; bool favorite; Bookmark({this.surah_no, this.verse_no, this.surah_name, this.favorite}); Bookmark.fromJson(Map<String, dynamic> jsonData) : surah_no = jsonData['surah_no'], verse_no = jsonData['verse_no'], surah_name = jsonData['surah_name'], favorite = jsonData['favorite']; Map<String, dynamic> toJson() => { 'surah_no': surah_no, 'verse_no': verse_no, 'surah_name': surah_name, 'favorite': favorite, }; } class _BookmarkScreenState extends State<BookmarkScreen> { List<Bookmark> bks = <Bookmark>[]; @override void initState() { super.initState(); _loadData(); } Future<List<Bookmark>> _loadData() async { SharedPreferences pref = await SharedPreferences.getInstance(); List<String> lb = pref.getStringList('bookmarks_key') ?? []; // 解析JSON字符串为Bookmark实例 bks = lb.map((jsonStr) { Map<String, dynamic> json = jsonDecode(jsonStr); return Bookmark.fromJson(json); }).toList(); return bks; } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text("Bookmark Screen")), body: Container( child: FutureBuilder( future: _loadData(), builder: (context, AsyncSnapshot<List<Bookmark>> snapshot) { if (!snapshot.hasData) { return const Center(child: CircularProgressIndicator()); } else { return GroupedListView<Bookmark, String>( elements: snapshot.data!, groupBy: (element) => element.surah_name!, groupComparator: (value1, value2) => value2.compareTo(value1), itemComparator: (item1, item2) => item1.verse_no.compareTo(item2.verse_no), order: GroupedListOrder.DESC, useStickyGroupSeparators: true, groupSeparatorBuilder: (String value) => Padding( padding: const EdgeInsets.all(8.0), child: Text( value, textAlign: TextAlign.center, style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold), ), ), itemBuilder: ((c, element) { return Card( elevation: 8.0, margin: const EdgeInsets.symmetric(horizontal: 10.0, vertical: 6.0), child: Container( child: ListTile( contentPadding: const EdgeInsets.symmetric(horizontal: 20.0, vertical: 10.0), title: Text(element.verse_no.toString()), ), ), ); }), ); } }, ), ), ); } }
关键优化说明
- 修复数据解析逻辑:通过
jsonDecode将字符串转为Map,再用Bookmark.fromJson生成有效实例。 - 替换属性访问方式:将
element['surah_name']改为element.surah_name,符合类实例的属性访问规则。 - 依赖FutureBuilder的
snapshot.data作为数据源,避免全局变量导致的状态不同步。 - 增加空值处理:用
?? []处理SharedPreferences返回null的情况,防止空指针异常。
内容的提问来源于stack exchange,提问作者Noor
相关产品推荐
相关产品推荐

