android - 状态更改后未调用 Flutter Bloc Builder 且未更新 UI

标签 android flutter mobile bloc chopper

我对 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/

相关文章:

android - Flutter - 'enableInteractiveSelection' 不适用于 EditableText

android-studio - 读取超时错误builder.jar(com.android.tools.build:builder:3.2.1)-Flutter-Android Studio

android - Firebase 数据排序

java - firebase android开发中通过循环从子节点获取特定数据

flutter - 单元测试配置单元抽象层

html - CSS 下拉菜单 - 移动支持

css - 触摸设备禁用元素悬停

html - 强制桌面浏览器显示网站的移动版本

android - 如何在 Android 中将图像转换为字节数组

android - 如何在不同的 Android Activity 之间交换一个对象?