我对 Flutter Bloc 包有疑问。主要想法是从 API 获取用户列表,我打开互联网查看我的错误状态是如何工作的,但是当 try/catch block 捕获错误时,我的 Bloc Builder 没有得到重建,我的 UI 没有改变,我有做热重启看看结果。
UserBloc 类:
import 'dart:io';
import 'package:chopper/chopper.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:listviewblocflutter/bloc/user/user_event.dart';
import 'package:listviewblocflutter/bloc/user/user_state.dart';
import 'package:listviewblocflutter/data/error/network_error.dart';
import 'package:listviewblocflutter/data/service/user_service.dart';
import 'package:listviewblocflutter/model/built/built_user.dart';
import 'package:built_collection/built_collection.dart';
class UserBloc extends Bloc<UserEvent, UserState> {
UserService _userService;
UserBloc() {
this._userService = UserService.create();
}
@override
UserState get initialState => UserInitial();
@override
Stream<UserState> mapEventToState(UserEvent event) async* {
yield UserLoading();
if (event is GetAllUsers) {
print("getallusers");
try {
final listOfUsers = await _userService.getAllUsers();
yield UsersLoaded(listOfUsers.body);
print("users loaded (userBloc)");
} catch (_) {
print("got an error (userBloc)");
yield UserLoadingError("Can't get all users!");
}
} else if (event is GetUserById) {
// single user event
}
}
}
用户事件类:
import 'package:equatable/equatable.dart';
abstract class UserEvent extends Equatable {
const UserEvent();
}
class GetAllUsers extends UserEvent {
const GetAllUsers();
@override
List<Object> get props => [];
}
class GetUserById extends UserEvent {
final int id;
const GetUserById(this.id);
@override
List<Object> get props => [id];
}
用户状态类:
import 'package:equatable/equatable.dart';
import 'package:flutter/cupertino.dart';
import 'package:listviewblocflutter/model/built/built_user.dart';
import 'package:built_collection/built_collection.dart';
@immutable
abstract class UserState extends Equatable {
const UserState();
}
class UserInitial extends UserState {
const UserInitial();
@override
List<Object> get props => [];
}
class UserLoading extends UserState {
const UserLoading();
@override
List<Object> get props => [];
}
class UserLoaded extends UserState {
final BuiltUser user;
const UserLoaded(this.user);
@override
List<Object> get props => [user];
}
class UsersLoaded extends UserState {
final BuiltList<BuiltUser> listOfUsers;
const UsersLoaded(this.listOfUsers);
@override
List<Object> get props => [listOfUsers];
}
class UserLoadingError extends UserState {
final String message;
const UserLoadingError(this.message);
@override
List<Object> get props => [message];
}
class UserEmpty extends UserState {
const UserEmpty();
@override
List<Object> get props => [];
}
我在 main.dart 文件中用 BlocProvider 包装了我的主页,以便在主页中访问我的 UserBloc:
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'ListView with BLoC pattern',
home: SafeArea(
child: Scaffold(
body: BlocProvider(
create: (context) => UserBloc(), child: HomePage()))),
);
}
}
试图将我的 HomePage 类设置为 StateLessWidget,但问题仍然存在,现在我的类是 StateFulWidget,但存在同样的问题。 我在 initState 方法中获取 AllUsers:
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:listviewblocflutter/bloc/bloc.dart';
import 'package:listviewblocflutter/model/built/built_user.dart';
import 'package:built_collection/built_collection.dart';
class HomePage extends StatefulWidget {
@override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
@override
void initState() {
BlocProvider.of<UserBloc>(context).add(GetAllUsers());
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Users"),
),
body: Container(
child: BlocListener<UserBloc, UserState>(
listener: (context, state) {
if (state is UserLoadingError) {
print("showing snackbar (listener)");
_showNetworkErrorSnackbar(context, state.message);
}
},
child: BlocBuilder<UserBloc, UserState>(
builder: (context, state) {
print("bloc builder");
if (state is UserLoading || state is UserInitial)
return _showLoadingStatus();
else if (state is UsersLoaded)
return _buildList(state.listOfUsers);
else if (state is UserEmpty || state is UserLoadingError) {
print("state is empty/error (builder)");
return _emptyListLayout();
}
return Center();
},
),
),
),
);
}
ListView _buildList(BuiltList<BuiltUser> listOfUsers) {
return ListView.builder(
itemCount: listOfUsers.length,
itemBuilder: (context, index) {
return Card(
child: ListTile(
leading: CircleAvatar(
backgroundColor: Colors.redAccent,
),
title: Padding(
padding: EdgeInsets.only(left: 10),
child: Text(
listOfUsers[index].username,
overflow: TextOverflow.ellipsis,
),
),
),
);
});
}
Widget _showLoadingStatus() {
return Center(
child: CircularProgressIndicator(),
);
}
Widget _emptyListLayout() {
return Center(
child: Text(
"List is empty ;(",
textAlign: TextAlign.center,
),
);
}
void _showNetworkErrorSnackbar(BuildContext context, String message) {
Scaffold.of(context).showSnackBar(SnackBar(
content: Text(message),
));
}
}
我的目标是在出现 UserLoadingError 状态时告诉用户列表为空并显示一个 snackbar ,但我只看到卡住的 LoadingIndicator
我在日志中的“打印”调试器说:
I/flutter (14034): 区 block 生成器
我/flutter (14034): getallusers
I/flutter (14034): 区 block 生成器
I/flutter (14034): 出现错误 (userBloc)
I/flutter (14034): 显示 snackbar (listener)
预期结果:
I/flutter (14034): 区 block 生成器
我/flutter (14034): getallusers
I/flutter (14034): 区 block 生成器
I/flutter (14034): 出现错误 (userBloc)
I/flutter (14034): showing snackbar (listener)///这条消息后应该出现一个 snackbar
I/flutter (14034): 区 block 生成器
I/flutter (14034): state is empty/error (builder)///在此消息之后应创建一个空列表布局
pubspecs.yaml fragment :
依赖项:
flutter :
SDK: flutter
cupertino_icons: ^0.1.3
斩波器:^3.0.2
平等的:^1.1.1
flutter_bloc: ^4.0.0
提供商:^4.1.1
内置值:^7.1.0
开发依赖:
斩波器发电机:^3.0.4
build_runner: ^1.10.0
内置值生成器:^7.1.0
flutter 测试:
SDK: flutter
我可以上传我的 UserService 类,使用 Chopper 从 API 获取用户,如果需要请告诉我。
最佳答案
终于发现问题了。问题出在我的 BlockBuilder if/else 树中,更准确地说:
if (state is UserLoading || state is UserInitial)
return _showLoadingStatus();
我变成了:
if (state is UserLoading)
return _showLoadingStatus();
现在问题消失了。
关于android - 状态更改后未调用 Flutter Bloc Builder 且未更新 UI,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61873678/