简体   繁体   中英

Unhandled Exception: Converting object to an encodable object failed: Instance of 'DateTime'

I have a Model of Task =>

class Task {


Task({this.isDone,this.name,this.time,this.priorityValue});
  final String name;
   bool isDone;
   final DateTime time;
   int priorityValue;



 factory Task.fromJson(Map<String, dynamic> jsonData) {
    return Task(
      name: jsonData['name'],
      isDone: false,
      time: jsonData['time'],
      priorityValue: jsonData['priorityValue'],
    );
  }

  toJSONEncodable() {
    Map<String, dynamic> m = new Map();

    m['name'] = name;
    m['isDone'] = isDone;
    m['time'] = time;
    m['priorityValue'] = priorityValue;

    return m;
  }

  static Map<String, dynamic> toMap(Task task) => {
        'name': task.name,
        'isDone': task.isDone,
        'time': task.time,
        'priorityValue': task.priorityValue,
      };
}

and When using the localStorage package to save some list of objects I got this error =>

(Flutter) Unhandled Exception: Converting object to an encodable object failed: Instance of 'DateTime'

_saveToStorage() {
storage.setItem('tasks', list.toJSONEncodable());
print("Saved");

}

i tried to use.toString() but then i get this error => type 'String' is not a subtype of type 'int' of 'index'

any Idea to save Datetime on LocalStorage package?

Update:

factory Task.fromJson(Map<String, dynamic> jsonData) {
return Task(
  name: jsonData['name'],
  isDone: false,
  time: jsonData["time"] == null ? null : DateTime.parse(jsonData["time"]),
  priorityValue: jsonData['priorityValue'],
);


 }

  toJSONEncodable() {
Map<String, dynamic> m = new Map();

m['name'] = name;
m['isDone'] = isDone;
m['time'] = time == null ? null : time.toIso8601String();
m['priorityValue'] = priorityValue;

return m;


 }

static Map<String, dynamic> toMap(Task task) => {
    'name': task.name,
    'isDone': task.isDone,
    'time': task.time,
    'priorityValue': task.priorityValue,
  };


var items = storage.getItem('tasks');
            if (items != null) {
              list.items = List<Task>.from(
                (items as List).map(
                  (item) => Task(
                    name: item['name'],
                    isDone: item['isDone'],
                    time: DateTime.parse(item['time']),
                    priorityValue: items['priorityValue'],
                  ),
                ),
              );
            }

after the update i got this error "type 'String' is not a subtype of type 'int' of 'index'"

Update2:

var items = storage.getItem('tasks');

            if (items != null) {
              final decodedJson = jsonDecode(items);
              list.items = (decodedJson as List)
                  .map((e) => Task.fromJson(e))
                  .toList();
              final task = list.items.first;
              print("${task.name}");
              // list.items = List<Task>.from(
              //   (items as List).map(
              //     (item) => Task(
              //       name: item['name'],
              //       isDone: item['isDone'],
              //       time: DateTime.parse(item['time']),
              //       priorityValue: items['priorityValue'],
              //     ),
              //   ),
              // );
            }

fter the second update i got "type '_InternalLinkedHashMap<String, dynamic>' is not a subtype of type 'String'"

Fixed

i changed the DaeTme toa String in the model and convert the time to a string when got it by

"${selectedDate.toLocal()}".split(' ')[0]

use toJson

"changeDate": changeDate == null? null: changeDate.toIso8601String(),

and fromJson

changeDate: json["changeDate"] == null? null: DateTime.parse(json["changeDate"]),

I'd highly recommend you to use Retrofit and json_serializable for describing your API

It could look like so:

import 'package:json_annotation/json_annotation.dart';

part 'task.g.dart';

@JsonSerializable(nullable: false, explicitToJson: true)
class Task {
  final String name;
  bool isDone;
  final DateTime time;
  int priorityValue;

  Task({this.isDone, this.name, this.time, this.priorityValue});

  factory Task.fromJson(Map<String, dynamic> json) => _$TaskFromJson(json);

  Map<String, dynamic> toJson() => _$TaskToJson(this);
}

after that you need to run build_runner :
flutter pub run build_runner build

and it will generate you both toJson and fromJson methods without any pain:

Task _$TaskFromJson(Map<String, dynamic> json) {
  return Task(
    isDone: json['isDone'] as bool,
    name: json['name'] as String,
    time: DateTime.parse(json['time'] as String),
    priorityValue: json['priorityValue'] as int,
  );
}

Map<String, dynamic> _$TaskToJson(Task instance) => <String, dynamic>{
      'name': instance.name,
      'isDone': instance.isDone,
      'time': instance.time.toIso8601String(),
      'priorityValue': instance.priorityValue,
    };

You can check out the test:

void main() {
  test('Task should be parsed from json', () {
    const json = '''
    [
      {
        "name": "testing",
        "isDone": false,
        "time": "2021-01-12T13:57:10.705476",
        "priorityValue": 0
      }
    ]
    ''';

    final List decodedJson = jsonDecode(json);
    final List<Task> list = decodedJson.map((e) => Task.fromJson(e)).toList();

    final Task task = list.first;

    expect(task.name, 'testing');
    expect(task.isDone, false);
    expect(task.time, DateTime.parse("2021-01-12T13:57:10.705476"));
    expect(task.priorityValue, 0);
  });
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM