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

Dart编码解码异常:String无法转为Map<String, dynamic>求助

问题分析与解决方案

问题描述

  • 调用encodeSelectedEvents后得到输出:"{\"2023-04-19 00:00:00.000Z\":[{\"title\":\"sdaads\"}]}"
  • 执行解码操作时触发异常:[ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: type 'String' is not a subtype of type 'Map<String, dynamic>'
  • 核心障碍:无法将String类型转换为Map<String, dynamic>,使用生成的转换函数仍未解决问题。

核心原因

代码中存在重复JSON编码的问题:

  • encodeSelectedEvents函数内部已经通过json.encode(encodedEvents)生成了JSON字符串
  • 存储到SharedPreferences时,又额外调用了json.encode(encodeSelectedEvents(...)),导致JSON字符串被再次编码
  • 最终存储的内容是一个被转义的字符串(而非原始JSON对象结构),解码时json.decode()返回的是String类型,无法直接转换为Map,触发类型不匹配异常。

修复步骤

  1. 移除重复编码:直接存储encodeSelectedEvents的返回值,无需二次调用json.encode
  2. (可选)统一日期格式:使用DateTime.toIso8601String()生成标准日期字符串,避免解析时的时区或格式问题

修正后的完整代码

import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'dart:convert';

class Event{
  final String title;
  Event({required this.title});

  Map<String, dynamic> toJson() => {
    'title': title,
  };

  factory Event.fromJson(Map<String, dynamic> json) {
    return Event(
      title: json['title'],
    );
  }
}

class CalendarPage extends StatefulWidget {
  const CalendarPage({Key? key}) : super(key: key);

  @override
  State<CalendarPage> createState() => _CalendarPageState();
}

class _CalendarPageState extends State<CalendarPage> {

  String encodeSelectedEvents(Map<DateTime, List<Event>> selectedEvents) {
    Map<String, List<Map<String, dynamic>>> encodedEvents = {};
    selectedEvents.forEach((key, value) {
      // 可选:使用标准ISO日期格式,提升解析可靠性
      encodedEvents[key.toIso8601String()] = value.map((event) => event.toJson()).toList();
    });
    return json.encode(encodedEvents);
  }

  Map<DateTime, List<Event>> decodeSelectedEvents(String jsonString) {
    Map<String, dynamic> decodedEvents = json.decode(jsonString);
    Map<DateTime, List<Event>> selectedEvents = {};
    decodedEvents.forEach((key, value) {
      DateTime dateTimeKey = DateTime.parse(key);
      selectedEvents[dateTimeKey] = List<Event>.from(value.map((event) => Event.fromJson(event)));
    });
    return selectedEvents;
  }

  Map<DateTime, List<Event>>? selectedEvents = {};

  DateTime today = DateTime.now();

  void _OnDaySelected(DateTime day, DateTime focusedDay) {
    setState(() {
      today = day;
    });
  }

  @override
  void initState() {
    super.initState();
    initializeDateFormatting("tr_TR");
    selectedEvents = {};
  }

  List<Event> _getEventsfromDay(DateTime day) {
    return selectedEvents![day]?? [];
  }

  @override
  Widget build(BuildContext context) {
    return Center(
        child: SingleChildScrollView(
          child: Column(
            children: [
              TableCalendar(
                locale: "tr_TR",
                firstDay: DateTime.utc(2023, 01, 01),
                lastDay: DateTime.utc(2025, 01, 01),
                focusedDay: today,
                headerStyle: HeaderStyle(
                  formatButtonVisible: false,
                  titleCentered: true,
                ),
                availableGestures: AvailableGestures.all,
                rowHeight: 35,
                onDaySelected: _OnDaySelected,
                selectedDayPredicate: (day) =>isSameDay(day,today),
                eventLoader: _getEventsfromDay,
              ),
              ElevatedButton(onPressed: () async{

                final secim = await Navigator.push(context,MaterialPageRoute(builder: (builder) => EventAddPage(date: today.toString().split(" ")[0],)));
                if (secim != false) {
                  final SharedPreferences prefs = await SharedPreferences.getInstance();

                  var events = prefs.getString('events');
                  // 首次初始化
                  if (events == null){
                    await prefs.setString("events", "{}");
                    selectedEvents = {};
                  }else {
                    selectedEvents = decodeSelectedEvents(events);
                  }

                  // 更新事件列表
                  if (selectedEvents == null) {
                    selectedEvents = {today: [Event(title: secim)]};
                  } else if (selectedEvents![today]?.isNotEmpty ?? false) {
                    selectedEvents![today]!.add(Event(title: secim));
                  } else {
                    selectedEvents![today] = [Event(title: secim)];
                  }
                  setState(() {});

                  // 移除重复的json.encode,直接存储encodeSelectedEvents的结果
                  await prefs.setString("events", encodeSelectedEvents(selectedEvents!));
                }
                },
                  child: Text("Seçili güne event ekle")
              ),
              ..._getEventsfromDay(today).map((Event event) => ListTile(title: Text(event.title),)),

            ],
          ),
        ),
    );
  }
}

// 补充EventAddPage的占位实现(原代码未提供)
class EventAddPage extends StatelessWidget {
  final String date;
  const EventAddPage({Key? key, required this.date}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("Add Event for $date")),
      body: Center(
        child: ElevatedButton(
          onPressed: () => Navigator.pop(context, "Sample Event"),
          child: Text("Add Event"),
        ),
      ),
    );
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 18:13:12