the following situation: I want to make a ToDo list with a Cubit. That the ToDo list does not disappear after leaving the app, I found the package hydrated Bloc. When I created the HydratedCubit with the 2 override methods for the FromJson and ToJson, creating them Inside the ToDoState and executed it, I got an exception, "Converting object to an encodable object failed: Instance of 'Todo'". After research I found out that JSON can't convert such a model and you have to overwrite these models with working From and To functions first. I tried this with the package "json serializable". Here I had to ask myself in which class I have to add the "@JsonSerializable()", inside the Todo model or the todo state, in which the error appears? I decided to add the @ for my todostate because adding it on the Todo model didn't change anything. After this package created me the "todo_list_state.g.dart" I don't get the error anymore, BUT: It also doesn't save the list, looks like HydratedCubit is being "ignored". Here a few code snippets:
First, I show you the Todo Model:
Uuid uuid = const Uuid();
class Todo extends Equatable {
final String id;
final String desc;
final double menge;
Todo( {
String? id,
required this.desc,
required this.menge,
}) : id = id ?? uuid.v4();
}
I left out the to string and props... As I mentioned before, I tried to add the JsonSerializableGenerator inside this class, but this didn't change something. Here is my TodoListState:
part of 'todo_list_cubit.dart';
@JsonSerializable()
class TodoListState extends Equatable {
final List<Todo> todos;
factory TodoListState.initial() {
return TodoListState(todos: []);
}
Map<String, dynamic>toMap() => _$FoodListStateToMap(this, food);
factory FoodListState.fromMap(Map<String, dynamic> map) => _$FoodListStateFromMap(map);
}
Here are the generated functions inside 'todo_list_state.g.dart':
TodoListState _$TodoListStateFromMap(Map<String, dynamic> map) {
return TodoListState (
todo: map['todo'] as List<TodoModel>,
);
}
Map<String, dynamic> _$TodoListStateToMap(TodoListState instance, List<TodoModel> todo) {
return {
'todo': todo,
};
}
At last here my Cubit functions where I override the From and To:
@override
TodoListState? fromJson(Map<String, dynamic> json) {
return TodoListState.fromMap(json);
}
@override
Map<String, dynamic>? toJson(TodoListStatestate) {
return state.toMap();
}
So does anybody know why my Hydrated Cubit doesn't save my list? Or do I have to convert the Model but just dont know how?... Appreciate your help. Thanks
Both model and states need to have toJson
and fromJson
methods. So the approach was right with using JsonSerializable
. But converting objects to and from json is a very important thing to understand how to do without codegen tools. Those can be boilerplate and not always converting correctly complex objects. When doing it manually, it's also easier to debug. So in your case, additions to the model would be:
class Todo extends Equatable {
final String id;
final String desc;
final double menge;
Todo( {
String? id,
required this.desc,
required this.menge,
}) : id = id ?? uuid.v4();
factory Todo.fromJson(Map<String, dynamic> json){
return Todo(id: json['id'],
desc: json['desc'],
menge: json['menge'],);
}
Map<String, dynamic> toJson() {
return {
'id': id,
'desc': desc,
'menge': menge,
};
}
}
Then, in your states (again, I am not going to use JsonSerializable
):
class TodoListState extends Equatable {
final List<Todo> todos;
TodoListState({this.todos = const <Todo>[]});
factory TodoListState.fromJson(Map<String, dynamic> json) {
var todos = <Todo>[];
for (var item in json['todos']) {
todos.add(Todo.fromJson(item));
}
return TodoListState(todos: todos);
}
Map<String, dynamic> toJson() {
var jsonTodoList = <Map<String, dynamic>>[];
for (var item in todos) {
jsonTodoList.add(item.toJson());
}
return {
'todos': jsonTodoList,
};
}
}
Then in your Cubit nothing changes
@override
TodoListState? fromJson(Map<String, dynamic> json) {
return TodoListState.fromJson(json);
}
@override
Map<String, dynamic>? toJson(TodoListState state) {
return state.toJson();
}
Except for you may want to add all sorts of null safety checks around the conversions, because I omitted all aspects not related to the topic of the question.