BLoC 产生新状态后 BlocBuilder() 未更新
BlocBuilder() not being updated after BLoC yielding new state
我是 flutter 上的 BLoC 模式的新手,我正在尝试使用它重建一个凌乱的 flutter 应用程序。目前,我打算获取用户应用程序列表并使用 ListView.builder() 显示它们。问题是每当我的 AppsBloc 的状态发生变化时,我的 StatelessWidget 都不会更新以显示新状态。我试过:
- 使用 main.dart 中的 MultiBlocProvider() 而不是将此 appsBloc 嵌套在包含整个应用程序的 themeBloc 中
- 返回列表而不是地图,即使我的辅助方法 returns 是正确的地图
- 使用 StatefulWidget,仅在 ListView 上使用 BlocProvider()...
我一直在阅读有关类似项目的这个问题,问题可能出在 Equatable 上。但是,由于我也是 Equatable 的新手,因此我无法识别出任何错误。我一直在 VScode 上调试项目,在 yield* 行设置断点,似乎没问题。尽管如此,小部件并没有得到重建:它一直显示对应于 InitialState 的文本。
此外,BLoC 不会在控制台上打印任何内容,即使所有状态都已覆盖 toString()
这些是我的 3 个 BLoC 文件:
apps_bloc.dart
import 'dart:async';
import 'package:bloc/bloc.dart';
import 'package:device_apps/device_apps.dart';
import 'package:equatable/equatable.dart';
part 'apps_event.dart';
part 'apps_state.dart';
class AppsBloc extends Bloc<AppsEvent, AppsState> {
@override
AppsState get initialState => AppsInitial();
@override
Stream<AppsState> mapEventToState(AppsEvent event) async* {
yield AppsLoadInProgress();
if (event is AppsLoadRequest) {
yield* _mapAppsLoadSuccessToState();
}
}
Stream<AppsState> _mapAppsLoadSuccessToState() async* {
try {
final allApps = await DeviceApps.getInstalledApplications(
onlyAppsWithLaunchIntent: true, includeSystemApps: true);
final listaApps = allApps
..sort((a, b) =>
a.appName.toLowerCase().compareTo(b.appName.toLowerCase()));
final Map<Application, bool> res =
Map.fromIterable(listaApps, value: (e) => false);
yield AppsLoadSuccess(res);
} catch (_) {
yield AppsLoadFailure();
}
}
}
apps_event.dart
part of 'apps_bloc.dart';
abstract class AppsEvent extends Equatable {
const AppsEvent();
@override
List<Object> get props => [];
}
class AppsLoadRequest extends AppsEvent {}
apps_state.dart
part of 'apps_bloc.dart';
abstract class AppsState extends Equatable {
const AppsState();
@override
List<Object> get props => [];
}
class AppsInitial extends AppsState {
@override
String toString() => "State: AppInitial";
}
class AppsLoadInProgress extends AppsState {
@override
String toString() => "State: AppLoadInProgress";
}
class AppsLoadSuccess extends AppsState {
final Map<Application, bool> allApps;
const AppsLoadSuccess(this.allApps);
@override
List<Object> get props => [allApps];
@override
String toString() => "State: AppLoadSuccess, ${allApps.length} entries";
}
class AppsLoadFailure extends AppsState {
@override
String toString() => "State: AppLoadFailure";
}
main_screen.dart
class MainScreen extends StatelessWidget {
const MainScreen({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return TabBarView(
children: <Widget>[
HomeScreen(),
BlocProvider(
create: (BuildContext context) => AppsBloc(),
child: AppsScreen(),
)
,
],
);
}
}
apps_screen.dart
class AppsScreen extends StatelessWidget {
const AppsScreen({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
margin: EdgeInsets.fromLTRB(30, 5, 10, 0),
child: Column(children: <Widget>[
Row(
children: <Widget>[
Text("Apps"),
],
),
Row(children: <Widget>[
Container(
width: MediaQuery.of(context).size.width - 50,
height: MediaQuery.of(context).size.height - 150,
child: BlocBuilder<AppsBloc, AppsState>(
builder: (BuildContext context, AppsState state) {
if (state is AppsLoadSuccess)
return Text("LOADED");
else if (state is AppsInitial)
return GestureDetector(
onTap: () => AppsBloc().add(AppsLoadRequest()),
child: Text("INITIAL"));
else if (state is AppsLoadInProgress)
return Text("LOADING...");
else if (state is AppsLoadFailure)
return Text("LOADING FAILED");
},
),
),
])
])),
);
}
}
在GestureDetector.onTap()
中你创建了一个新的AppsBloc()
,这是错误的。所以,你需要:
apps_screen.dart:
AppsBloc _appsBloc;
@override
void initState() {
super.initState();
_appsBloc = BlocProvider.of<AppsBloc>(context);
}
//...
@override
Widget build(BuildContext context) {
//...
return GestureDetector(
onTap: () => _appsBloc.add(AppsLoadRequest()),
child: Text("INITIAL")
);
//...
}
或者即使没有 _appsBloc
字段,您也可以这样做:
BlocProvider.of<AppsBloc>(context).add(AppsLoadRequest())
我是 flutter 上的 BLoC 模式的新手,我正在尝试使用它重建一个凌乱的 flutter 应用程序。目前,我打算获取用户应用程序列表并使用 ListView.builder() 显示它们。问题是每当我的 AppsBloc 的状态发生变化时,我的 StatelessWidget 都不会更新以显示新状态。我试过:
- 使用 main.dart 中的 MultiBlocProvider() 而不是将此 appsBloc 嵌套在包含整个应用程序的 themeBloc 中
- 返回列表而不是地图,即使我的辅助方法 returns 是正确的地图
- 使用 StatefulWidget,仅在 ListView 上使用 BlocProvider()...
我一直在阅读有关类似项目的这个问题,问题可能出在 Equatable 上。但是,由于我也是 Equatable 的新手,因此我无法识别出任何错误。我一直在 VScode 上调试项目,在 yield* 行设置断点,似乎没问题。尽管如此,小部件并没有得到重建:它一直显示对应于 InitialState 的文本。
此外,BLoC 不会在控制台上打印任何内容,即使所有状态都已覆盖 toString()
这些是我的 3 个 BLoC 文件:
apps_bloc.dart
import 'dart:async';
import 'package:bloc/bloc.dart';
import 'package:device_apps/device_apps.dart';
import 'package:equatable/equatable.dart';
part 'apps_event.dart';
part 'apps_state.dart';
class AppsBloc extends Bloc<AppsEvent, AppsState> {
@override
AppsState get initialState => AppsInitial();
@override
Stream<AppsState> mapEventToState(AppsEvent event) async* {
yield AppsLoadInProgress();
if (event is AppsLoadRequest) {
yield* _mapAppsLoadSuccessToState();
}
}
Stream<AppsState> _mapAppsLoadSuccessToState() async* {
try {
final allApps = await DeviceApps.getInstalledApplications(
onlyAppsWithLaunchIntent: true, includeSystemApps: true);
final listaApps = allApps
..sort((a, b) =>
a.appName.toLowerCase().compareTo(b.appName.toLowerCase()));
final Map<Application, bool> res =
Map.fromIterable(listaApps, value: (e) => false);
yield AppsLoadSuccess(res);
} catch (_) {
yield AppsLoadFailure();
}
}
}
apps_event.dart
part of 'apps_bloc.dart';
abstract class AppsEvent extends Equatable {
const AppsEvent();
@override
List<Object> get props => [];
}
class AppsLoadRequest extends AppsEvent {}
apps_state.dart
part of 'apps_bloc.dart';
abstract class AppsState extends Equatable {
const AppsState();
@override
List<Object> get props => [];
}
class AppsInitial extends AppsState {
@override
String toString() => "State: AppInitial";
}
class AppsLoadInProgress extends AppsState {
@override
String toString() => "State: AppLoadInProgress";
}
class AppsLoadSuccess extends AppsState {
final Map<Application, bool> allApps;
const AppsLoadSuccess(this.allApps);
@override
List<Object> get props => [allApps];
@override
String toString() => "State: AppLoadSuccess, ${allApps.length} entries";
}
class AppsLoadFailure extends AppsState {
@override
String toString() => "State: AppLoadFailure";
}
main_screen.dart
class MainScreen extends StatelessWidget {
const MainScreen({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return TabBarView(
children: <Widget>[
HomeScreen(),
BlocProvider(
create: (BuildContext context) => AppsBloc(),
child: AppsScreen(),
)
,
],
);
}
}
apps_screen.dart
class AppsScreen extends StatelessWidget {
const AppsScreen({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
margin: EdgeInsets.fromLTRB(30, 5, 10, 0),
child: Column(children: <Widget>[
Row(
children: <Widget>[
Text("Apps"),
],
),
Row(children: <Widget>[
Container(
width: MediaQuery.of(context).size.width - 50,
height: MediaQuery.of(context).size.height - 150,
child: BlocBuilder<AppsBloc, AppsState>(
builder: (BuildContext context, AppsState state) {
if (state is AppsLoadSuccess)
return Text("LOADED");
else if (state is AppsInitial)
return GestureDetector(
onTap: () => AppsBloc().add(AppsLoadRequest()),
child: Text("INITIAL"));
else if (state is AppsLoadInProgress)
return Text("LOADING...");
else if (state is AppsLoadFailure)
return Text("LOADING FAILED");
},
),
),
])
])),
);
}
}
在GestureDetector.onTap()
中你创建了一个新的AppsBloc()
,这是错误的。所以,你需要:
apps_screen.dart:
AppsBloc _appsBloc;
@override
void initState() {
super.initState();
_appsBloc = BlocProvider.of<AppsBloc>(context);
}
//...
@override
Widget build(BuildContext context) {
//...
return GestureDetector(
onTap: () => _appsBloc.add(AppsLoadRequest()),
child: Text("INITIAL")
);
//...
}
或者即使没有 _appsBloc
字段,您也可以这样做:
BlocProvider.of<AppsBloc>(context).add(AppsLoadRequest())