[英]Flutter bloc not working after hot reload
我的应用程序使用 bloc/cubit 显示 Todo 项目列表,在我热重载/热重启应用程序之前工作正常!
我有两个按钮,当我单击这些按钮时,cubit state 被设置为有 3 个待办事项。 此外,我有两个周期性计时器,它再次将 cubit state 设置为只有 1 或 0 个待办事项。 所以项目的数量不断地从 1 变为 0 直到,或者如果我按下一个按钮它瞬间变成 3。
这在热重载/重启之前工作正常,之后按钮不再工作。 但是,定期更改确实有效。 我只能通过在我的“MyApp”基本小部件中创建我的 ToDoBloc 作为字段初始化器来缓解这个问题。
主要.dart:
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:todo/todo_api_controller.dart';
import 'package:todo/todo_bloc.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
MyApp({Key? key}) : super(key: key);
late TodoBloc _todoBloc; //!!----IF I CREATE THE TODOBLOC HERE EVERYTHING WORKS--!!
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
_todoBloc = TodoBloc(
apiController: TodoApiController(),
);
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(_todoBloc),
);
}
}
class MyHomePage extends StatelessWidget {
TodoBloc _todoBloc;
MyHomePage(this._todoBloc, {Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: BlocProvider<TodoBloc>.value(
value: _todoBloc,
child: BlocBuilder<TodoBloc, TodoBlocState>(
builder: (context, state) {
return Builder(
builder: (context) => Column(
mainAxisSize: MainAxisSize.min,
children: [
TextButton(
onPressed: () => context.read<TodoBloc>().LoadAll(),
child: Text(
'pressme',
style: TextStyle(color: Colors.red),
)),
ListView.builder(
shrinkWrap: true,
itemCount: state.todos.length,
itemBuilder: (context, index) {
var todo = state.todos[index];
return CheckboxListTile(
value: todo.isFinished,
onChanged: (newvalue) {},
);
}),
],
));
},
),
),
floatingActionButton: FloatingActionButton(
onPressed: () async {
await _todoBloc.LoadAll();
},
),
);
}
}
todo_api_controller.dart
class TodoApiController {
List<Todo> GetAll() {
return [
Todo(id: "asfsdf", name: "this is todo", isFinished: true, finishedOn: DateTime.now()),
Todo(id: "asfsdf", name: "this is todo", isFinished: true, finishedOn: DateTime.now()),
];
}
void Delete(String id) {}
void Update(Todo todo) {}
Todo Create() {
return Todo(id: "asdfsdf");
}
}
class Todo {
final String id;
String name;
bool isFinished;
DateTime? finishedOn;
Todo({required String id, String name = "", bool isFinished = false, DateTime? finishedOn = null})
: id = id,
name = name,
isFinished = isFinished,
finishedOn = finishedOn {}
}
todo_bloc.dart
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:todo/todo_api_controller.dart';
class TodoBloc extends Cubit<TodoBlocState> {
static int numberOfInstances = 0;
int myInstance = -1;
TodoApiController _apiController;
List<Todo> todos = [];
TodoBloc({required TodoApiController apiController})
: _apiController = apiController,
super(TodoBlocState(todos: [TodoItemState(id: "asdfsdf", name: "sdfsdf", isFinished: true, finishedOn: null)])) {
numberOfInstances++;
myInstance = numberOfInstances;
Timer.periodic(Duration(seconds: 2), (s) => emit(TodoBlocState()));
Future.delayed(
Duration(seconds: 1),
() => Timer.periodic(
Duration(seconds: 2), (s) => emit(TodoBlocState(todos: [TodoItemState(id: "asdfsdf", name: "sdfsdf", isFinished: true, finishedOn: null)]))));
}
Future<void> LoadAll() async {
/* var newTodos = _apiController.GetAll();
todos.clear();
todos.addAll(newTodos);
var newState = MakeState();
emit(newState);*/
emit(TodoBlocState(todos: [
TodoItemState(id: "asdfsdf", name: "sdfsdf", isFinished: true, finishedOn: null),
TodoItemState(id: "asdfsdf", name: "sdfsdf", isFinished: true, finishedOn: null),
TodoItemState(id: "asdfsdf", name: "sdfsdf", isFinished: true, finishedOn: null),
]));
}
TodoBlocState MakeState() {
return TodoBlocState(
todos: todos
.map((e) => TodoItemState(
id: e.id,
finishedOn: e.finishedOn,
isFinished: e.isFinished,
name: e.name,
))
.toList(),
);
}
}
class TodoBlocState {
final List<TodoItemState> todos = [];
TodoBlocState({List<TodoItemState>? todos}) {
this.todos.addAll(todos ?? []);
}
}
class TodoItemState {
final String id;
final String name;
final bool isFinished;
final DateTime? finishedOn;
TodoItemState({required this.id, required this.name, required this.isFinished, required this.finishedOn});
}
我无法弄清楚这是为什么,尤其是热重启时,因为这应该重置所有应用程序 state。
编辑:问题在热重载(不是热重启)后出现,但不能通过热重启解决
EDIT2:通过向 MyHomePage class 添加 GlobalKey() 来解决问题。虽然我不明白为什么。 谁可以给我解释一下这个?
发生这种情况是因为您正在构建 function 中初始化TodoBloc
。热重载会重建您的小部件,因此它会触发对其build
函数的新调用。
您应该将其转换为StatefulWidget
并在 initState TodoBloc
中初始化您的initState
:
class MyApp extends StatefulWidget {
MyApp({Key? key}) : super(key: key);
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
late TodoBloc _todoBloc;
@override
void initState() {
super.initState();
_todoBloc = TodoBloc(
apiController: TodoApiController(),
);
}
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(_todoBloc),
);
}
}
您真的不需要在小部件树的顶部声明和初始化您的TodoBloc
,然后将它一直向下传递。 BlocProvider
创建一个可通过context.read<TodoBloc>()
访问的新实例。
您的MyApp
可能看起来像这样。
class MyApp extends StatelessWidget {
MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: BlocProvider(
create: (context) => TodoBloc(apiController: TodoApiController()), // this is your bloc being created and initialized
child: MyHomePage(),
),
);
}
}
MyHomePage
可以简化。 请注意缺少BlocProvider.value
和Builder
。 您只需要一个BlocBuilder
并且始终可以使用context.read<TodoBloc>()
访问TodoBloc
的正确实例。
class MyHomePage extends StatelessWidget {
MyHomePage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: BlocBuilder<TodoBloc, TodoBlocState>(
builder: (context, state) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
TextButton(
onPressed: () => context.read<TodoBloc>().LoadAll(),
child: Text(
'pressme',
style: TextStyle(color: Colors.red),
),
),
ListView.builder(
shrinkWrap: true,
itemCount: state.todos.length,
itemBuilder: (context, index) {
var todo = state.todos[index];
return CheckboxListTile(
value: todo.isFinished,
onChanged: (newvalue) {},
);
},
),
],
);
},
),
floatingActionButton: FloatingActionButton(
onPressed: () async {
await context.read<TodoBloc>().LoadAll();
},
),
);
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.