繁体   English   中英

首先:将 object 转换为可编码的 object 失败 - 然后:HydratedCubit 未水合

[英]First: Converting object to an encodable object failed - then: HydratedCubit isn't hydrated

以下情况:我想用 Cubit 做一个 ToDo 列表。 离开应用程序后待办事项列表不会消失,我找到了 package hydrated Bloc。 当我使用 FromJson 和 ToJson 的 2 个覆盖方法创建 HydratedCubit,在 ToDoState 内部创建它们并执行它时,我得到一个异常,“将 object 转换为可编码的 object 失败:'Todo' 的实例”。 经过研究,我发现 JSON 无法转换这样的 model,您必须先使用有效的 From 和 To 函数覆盖这些模型。 我用 package “json 可序列化”试过这个。 在这里我不得不问自己在哪个class我必须在Todo model或todo state中添加“@JsonSerializable()”,其中出现错误? 我决定为我的 todostate 添加 @,因为将它添加到 Todo model 并没有改变任何东西。 在这个 package 为我创建了“todo_list_state.g.dart”之后,我不再收到错误,但是:它也没有保存列表,看起来 HydratedCubit 被“忽略”了。 这里有一些代码片段:

首先,我向您展示 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();

  
}

我遗漏了 to string 和 props...正如我之前提到的,我试图在这个 class 中添加 JsonSerializableGenerator,但这并没有改变什么。 这是我的 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);

  }

以下是“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,
    };
}

最后,在这里我的 Cubit 函数覆盖了 From 和 To:

  @override
  TodoListState? fromJson(Map<String, dynamic> json) {
    return TodoListState.fromMap(json);
  }

  @override
  Map<String, dynamic>? toJson(TodoListStatestate) {
    return state.toMap();
  }

那么有人知道为什么我的 Hydrated Cubit 没有保存我的列表吗? 还是我必须转换 Model 但不知道如何转换?...感谢您的帮助。 谢谢

不幸的是,您不能使用hydrated_bloc保留列表直到日期


请务必注意, Hydrated_bloc不适用于涉及存储complex datalists的用例。 只有在data simple的情况下才可以使用。

上述陈述的证明:

  1. 我们如何在 hydrated bloc #2324 中保留列表 - 未决问题
  2. 问题 [hydrated_bloc] 复杂的例子 #2392

解决方案

对于此类要求,我建议您使用shared_preferences


持久化待办事项的单个实例

TodoCubit.dart

class TodoCubit extends HydratedBloc<TodoCubit, TodoState> {
  TodoCubit() : super(ToDoInitial());

  @override
  TodoState? fromJson(Map<String, dynamic> json) {
    return TodoState.fromJson(json);
  }

  @override
  Map<String, dynamic>? toJson(TodoState state) {
    return state.toJson();
  }

  saveTodo(String todo, String date) {
    emit(TodoState(presentTodo: Todo(todo: todo, day: date)));
  }
}

ToDoState.dart


class TodoState extends Equatable {
  final Todo presentTodo;

  const TodoState({required this.presentTodo});
  factory TodoState.fromJson(Map<String, dynamic> json) {
    return TodoState(presentTodo: Todo(todo: json['todo'], day: json['day']));
  }
  Map<String, dynamic> toJson() =>
      {'todo': presentTodo.todo, 'day': presentTodo.day};

  @override
  List<Object?> get props => [presentTodo];
}

class Todo {
  String todo;
  String day;
  Todo({required this.todo, required this.day});
  @override
  String toString() {
    return "todo: " + todo + " day: " + day;
  }
}

class ToDoInitial extends TodoState {
  ToDoInitial() : super(presentTodo: Todo(todo: '', day: ''));
}

家.dart

              return Center(
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: [
                    const SizedBox(height: 10),
                    Text(state.presentTodo.toString()),
                    ElevatedButton(
                      style: Constants.kElevatedButtonStyle,
                      onPressed: () {
                        context
                            .read<TodoCubit>()
                            .saveTodo('Drink Water ', 'Tuesday');
                      },
                      child: const Text(
                        'Add Dummy Todo',
                        style: TextStyle(
                            fontSize: 18, fontWeight: FontWeight.bold),
                      ),
                    ),
                  ],
                ),
              );

主要.dart

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  HydratedBloc.storage = await HydratedStorage.build(
    storageDirectory: await getTemporaryDirectory(),
  );
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return BlocProvider(
      create: (context) => TodoCubit(),
      child: MaterialApp(
        debugShowCheckedModeBanner: false,
        theme: ThemeData(
          appBarTheme: const AppBarTheme()
              .copyWith(backgroundColor: const Color.fromRGBO(18, 26, 28, 1)),
          primarySwatch: Colors.blue,
        ),
        home: const Home(),
      ),
    );
  }
}

Output:

在此处输入图像描述

model 和 states 都需要有toJsonfromJson方法。 因此,使用JsonSerializable的方法是正确的。 但是,将对象与 json 相互转换是了解如何在没有代码生成工具的情况下如何做的一件非常重要的事情。 这些可能是样板文件,并不总是能正确转换复杂的对象。 手动执行时,调试也更容易。 因此,在您的情况下,对 model 的添加将是:

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,
    };
  }
}

然后,在您的状态下(同样,我不会使用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,
    };
  }
}

然后在你的手肘中没有任何变化

  @override
  TodoListState? fromJson(Map<String, dynamic> json) {
    return TodoListState.fromJson(json);
  }

  @override
  Map<String, dynamic>? toJson(TodoListState state) {
    return state.toJson();
  }

除了你可能想在转换周围添加各种 null 安全检查,因为我省略了与问题主题无关的所有方面。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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