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

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},...]

错误原因

  1. 数据解析失效:_loadData方法仅将SharedPreferences中的字符串直接存入列表,随后创建空的Bookmark对象,未将JSON字符串解析为带有效属性的Bookmark实例,导致所有对象属性为null。
  2. 属性访问方式错误: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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 21:54:24