Flutter BlocBuilder 构建器仅在最初被调用并且不会对状态变化做出反应

Flutter BlocBuilder builder gets called only initially and doesn't react to state change

我最近才开始接触 Flutter。 BLoC 确实有一个陡峭的学习曲线...

正如标题所示,当应用程序启动时,BlocBuilder 逻辑仅正确执行一次。但是,之后 UI 不会根据状态更改进行重建。尽管所有事件都已发出,状态也发生了变化。

在此先感谢您的帮助!

这是我的 'main.dart':

import 'package:co_flutter/auth/authentication_bloc.dart';
import 'package:co_flutter/auth/authentication_event.dart';
import 'package:co_flutter/auth/authentication_state.dart';
import 'package:co_flutter/auth/login/login_bloc.dart';
import 'package:co_flutter/auth/signup/signup_page.dart';
import 'package:co_flutter/loading_indicator.dart';
import 'package:co_flutter/splash_page.dart';
import 'package:co_flutter/user_repository.dart';

import 'package:flutter/material.dart';
import 'package:bloc/bloc.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

import 'auth/login/login_page.dart';

class SimpleBlocObserver extends BlocObserver {
  @override
  void onCreate(BlocBase bloc) {
    super.onCreate(bloc);
    print('onCreate -- ${bloc.runtimeType}');
  }

  @override
  void onEvent(Bloc bloc, Object? event) {
    super.onEvent(bloc, event);
    print('onEvent -- ${bloc.runtimeType}, $event');
  }

  @override
  void onTransition(Bloc bloc, Transition transition) {
    super.onTransition(bloc, transition);
    print('onTransition -- ${bloc.runtimeType}, $transition');
  }

  @override
  void onChange(BlocBase bloc, Change change) {
    super.onChange(bloc, change);
    print('onChange -- ${bloc.runtimeType}, $change');
  }

  @override
  void onError(BlocBase bloc, Object error, StackTrace stackTrace) {
    print('onError -- ${bloc.runtimeType}, $error');
    super.onError(bloc, error, stackTrace);
  }

  @override
  void onClose(BlocBase bloc) {
    super.onClose(bloc);
    print('onClose -- ${bloc.runtimeType}');
  }
}

void main() {
  Bloc.observer = SimpleBlocObserver();
  runApp(MyApp(
    userRepository: UserRepository(),
  ));
}

class MyApp extends StatefulWidget {
  final UserRepository userRepository;

  MyApp({Key? key, required this.userRepository}) : super(key: key);

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  late AuthenticationBloc authenticationBloc;
  UserRepository get userRepository => widget.userRepository;

  @override
  void initState() {
    authenticationBloc = AuthenticationBloc(userRepository: userRepository);
    authenticationBloc.add(AppStarted());
    super.initState();
  }

  @override
  void dispose() {
    authenticationBloc.close();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return MultiBlocProvider(
      providers: [
        BlocProvider<AuthenticationBloc>(
          create: (BuildContext context) => authenticationBloc,
        ),
        BlocProvider<LoginBloc>(
          create: (BuildContext context) => LoginBloc(
              userRepository: userRepository,
              authenticationBloc: authenticationBloc),
        ),
      ],
      child: MaterialApp(
        title: 'My App',
        theme: ThemeData(
          primarySwatch: Colors.indigo,
        ),
        home: BlocBuilder<AuthenticationBloc, AuthenticationState>(
          builder: (BuildContext context, AuthenticationState state) {
            if (state is AuthenticationUninitialized) {
              return SplashPage();
            }
            if (state is AuthenticationAuthenticated) {
              return Dashboard(
                title: 'Dashboard',
              );
            }
            if (state is AuthenticationUnauthenticated) {
              return LoginPage(
                userRepository: userRepository,
              );
            }
            if (state is AuthenticationLoading) {
              return LoadingIndicator();
            }
            // else {
            // return Text('Error');
            // }
            return BlocBuilder<LoginBloc, LoginState>(
              builder: (context, state) {
                if (state is LoginToSignup) {
                  return SignUpPage();
                } else
                  return SizedBox.shrink();
              },
            );
          },
        ),
      ),
    );
  }
}

class Dashboard extends StatelessWidget {
  final String title;

  const Dashboard({Key? key, required this.title}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final AuthenticationBloc authenticationBloc =
        BlocProvider.of<AuthenticationBloc>(context);

    return Scaffold(
      appBar: AppBar(
        title: Text('Dashboard'),
      ),
      body: Container(
        child: Center(
          child: ElevatedButton(
            child: Text('logout'),
            onPressed: () {
              authenticationBloc.add(LoggedOut());
            },
          ),
        ),
      ),
    );
  }
}

authentication_bloc

import 'dart:async';

import 'package:co_flutter/auth/authentication_event.dart';
import 'package:co_flutter/auth/authentication_state.dart';
import 'package:bloc/bloc.dart';
import '../user_repository.dart';

class AuthenticationBloc
    extends Bloc<AuthenticationEvent, AuthenticationState> {
  UserRepository userRepository;

  AuthenticationBloc({required this.userRepository})
      : super(AuthenticationUninitialized()) {
    userRepository = UserRepository();
  }

  @override
  Stream<AuthenticationState> mapEventToState(
    AuthenticationEvent event,
  ) async* {
    if (event is AppStarted) {
      final bool hasToken = await userRepository.hasToken();

      if (hasToken) {
        yield AuthenticationAuthenticated();
      } else {
        yield AuthenticationUnauthenticated();
      }
    }

    if (event is LoggedIn) {
      yield AuthenticationLoading();
      await userRepository.persistToken(event.token, event.userId);
      yield AuthenticationAuthenticated();
    }

    if (event is LoggedOut) {
      yield AuthenticationLoading();
      await userRepository.deleteToken();
      yield AuthenticationUnauthenticated();
    }
  }
}

authentication_event

import 'package:equatable/equatable.dart';

abstract class AuthenticationEvent extends Equatable {
  @override
  List<Object> get props => [];
}

class AppStarted extends AuthenticationEvent {
  @override
  String toString() => 'AppStarted';
}

class LoggedIn extends AuthenticationEvent {
  final String token;
  final String userId;

  LoggedIn({required this.token, required this.userId});

  @override
  String toString() => 'LoggedIn { token: $token}';
}

class LoggedOut extends AuthenticationEvent {
  @override
  String toString() => 'LoggedOut';
}

authentication_state

import 'package:equatable/equatable.dart';

abstract class AuthenticationState extends Equatable {
  const AuthenticationState();
}

class AuthenticationUninitialized extends AuthenticationState {
  @override
  List<Object> get props => [];
}

class AuthenticationLoading extends AuthenticationState {
  @override
  List<Object> get props => [];
}

class AuthenticationAuthenticated extends AuthenticationState {
  @override
  List<Object> get props => [];
}

class AuthenticationUnauthenticated extends AuthenticationState {
  @override
  List<Object> get props => [];
}

问题就在这里。您已经创建了一个集团:

authenticationBloc = AuthenticationBloc(userRepository: userRepository);

您正在尝试再次创建它。

要修复它,请替换此代码:

BlocProvider<AuthenticationBloc>(
                  create: (BuildContext context) => authenticationBloc,
                ),

有了这个:

BlocProvider<AuthenticationBloc>.value(
          value: authenticationBloc,
        ),

将 bloc 传递到 bloc builder

BlocBuilder<AuthenticationBloc, AuthenticationState>(
 bloc: authenticationBloc,

在处理函数中使用后,不要忘记处理 bloc authenticationBloc。