Flutter Bloc状态更改未使用get_it更新UI

时间:2020-05-17 12:09:04

标签: flutter bloc service-locator

我一直在使用此登录教程和resocoder干净体系结构教程的组合来构建登录/身份验证功能。它有99%的工作正常,但是对按下LoginButton的响应不正确。

由于某些原因,当LoginBloc调用AuthenticationBloc.add(loggedin())时,AuthenticationBloc产生的AuthenticationAuthenticated()状态就很好,但是Main.dart中的BlocBuilder没有收到状态更改。产生OnTransition时,甚至会触发SimpleBlocDelegate内部的AuthenticationAuthenticated,但是BlocBuilder不会执行任何操作。

Main.dart看起来像这样:

import 'package:bloc/bloc.dart';
import 'package:flutter_app/dependency_injector.dart' as di;
import 'package:flutter_app/features/login/presentation/pages/login_screen.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'features/login/presentation/bloc/user_login_bloc.dart';
import 'features/login/presentation/bloc/user_login_events.dart';
import 'features/login/presentation/bloc/user_login_states.dart';

class SimpleBlocDelegate extends BlocDelegate {
  @override
  void onEvent(Bloc bloc, Object event) {
    print(event);
    super.onEvent(bloc, event);
  }

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

  @override
  void onError(Bloc bloc, Object error, StackTrace stackTrace) {
    print(error);
    super.onError(bloc, error, stackTrace);
  }
}

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await di.init(); //Dependency Injection using get_it
  BlocSupervisor.delegate = SimpleBlocDelegate();
  runApp(
    BlocProvider<UserAuthenticationBloc>(
      create: (_) => sl<UserAuthenticationBloc>()..add(AppStarted()),
      child: App(),
    ),
  );
}

class App extends StatelessWidget {
  App({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: BlocBuilder<UserAuthenticationBloc, AuthenticationState>(
        builder: (context, state) {
          if (state is AuthenticationAuthenticated) {
            return Container(
              child: HomePage(); // THIS NEVER HAPPENS, even though AuthBloc yields the State
          }
          if (state is AuthenticationUnauthenticated) {
            return LoginScreen(); // THIS yeilds fine when AppStarted in passed on init.
          }
          if (state is AuthenticationLoading) {
            return LoadingIndicator();
          }
          return Scaffold(
            body: SplashPage();
          )
        },
      ),
    );
  }
}

我只能认为这与get_it有关。依赖注入看起来像这样:

final sl = GetIt.instance;

Future<void> init() async {
  sl.registerFactory(
    () => UserAuthenticationBloc(
      getCachedUser: sl(),
    ),
  );

  sl.registerFactory(
    () => LoginBloc(authenticationBloc: sl(), getUserFromEmailAndPassword: sl()),
  );
...
}

,然后在loginscreen的小部件树中创建LoginBloc,因此可用于登录表单。

class LoginScreen extends StatelessWidget {
  LoginScreen({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: BlocProvider<LoginBloc>(
        create: (_) => sl<LoginBloc>(),
        child: LoginForm(), //login form
      ),
    );
  }
}

两次编辑: 1.我将依赖项注入文件中的UserAuthenticationBloc从工厂更改为懒惰...现在可以工作了。但是,我听说对带Streams的类使用单例会导致内存泄漏?我想这意味着LoginBloc不在与Main.dart正在监听的AuthBloc实例通话吗?我不知道如何确保没有单例...

  1. UserAuthenticationBloc的代码:
    class UserAuthenticationBloc extends Bloc<AuthenticationEvent, AuthenticationState> {
      final GetCachedUser getCachedUser;
      UserAuthenticationBloc({
        @required GetCachedUser getCachedUser,
      })  : assert(getCachedUser != null),
            getCachedUser = getCachedUser;

      @override
      AuthenticationState get initialState => AuthenticationUninitialized();

      @override
      Stream<AuthenticationState> mapEventToState(AuthenticationEvent event) async* {
        if (event is AppStarted) {
             yield AuthenticationUnauthenticated();
          }
        }

        if (event is LoggedIn) {
          yield AuthenticationAuthenticated(); //this fires.
        }
      }
    }

1 个答案:

答案 0 :(得分:0)

我在项目中遇到了同样的问题。我使用的是同一堆栈,当我从另一个集团添加事件时,UI也看不到任何更改。我使用的临时解决方案-我使用GlobalKey<ScaffoldState>将上下文传递给该集团。因此,UI和Bloc使用相同的上下文。您可以在LoginBloc中使用它:

BlocProvider.of<UserAuthenticationBloc>(yourScaffoldKey.currentContext).add(LoggedIn event)