flutter - 使用 flutter_bloc 构建 Flutter 应用程序的架构

标签 flutter dart bloc

我必须使用 Flutter 开发一个简单的应用程序,并且我正在第一次尝试 bloc 模式。我正在使用 flutter_bloc 包,但我有两个主要问题并陷入困境:

  1. 应用程序中的所有屏幕都有依赖于存储库向服务器发出请求的 block ,对于每个请求我都需要一个 token 。我在 authentication_bloc (登录)处获取 token ,但我无法将该 token 共享给所有 block ,除非我使它们依赖于 auth_bloc(具有存储 token 的用户模型的 block )。对于一个简单的应用程序,也许它可以工作,但是如果除了 auth_bloc 之外,其他 block 还有更多的 block 依赖项,那么将所有 block 作为依赖项注入(inject)可能会变得一团糟。什么替代方案可能是一个好的解决方案?

  2. 对于导航,我有一个用于底部导航栏的bloc。但我希望选项卡上的所有屏幕都可以调用底部栏 block 的 change_tab() 函数。同样的问题,如果其他 block 依赖于底部栏 block ,我只能在底部栏 block 添加事件。我不想将身份验证 block 和底部栏 block 添加为管理所有屏幕的所有 block 的依赖项。

我很欣赏建议、替代方案或文档,我可以在其中学习为比示例显示的稍微复杂一点的应用程序构建良好的架构 here

最佳答案

您可以将 token 存储在Repository中,例如userRepository.persistToken(event.token)await userRepository.deleteToken();< br/> 存储库的行为类似于存储库模式。您不需要知道数据来自云端还是本地数据库
在下面的示例中,userRepository 可以是应用程序级别,因此所有 block 都可以使用它
完整示例代码 https://github.com/felangel/bloc/blob/master/examples/flutter_login/lib/authentication/authentication_bloc.dart
代码片段

void main() {
  BlocSupervisor.delegate = SimpleBlocDelegate();
  final userRepository = UserRepository();
  runApp(
    BlocProvider<AuthenticationBloc>(
      create: (context) {
        return AuthenticationBloc(userRepository: userRepository)
          ..add(AppStarted());
      },
      child: App(userRepository: userRepository),
    ),
  );
}

...

import 'package:meta/meta.dart';
import 'package:bloc/bloc.dart';
import 'package:user_repository/user_repository.dart';

import 'package:flutter_login/authentication/authentication.dart';

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

  AuthenticationBloc({@required this.userRepository})
      : assert(userRepository != null);

  @override
  AuthenticationState get initialState => AuthenticationUninitialized();

  @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);
      yield AuthenticationAuthenticated();
    }

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

您可以使用 MultiBlocProvider 在应用程序级别包装您的 block
下面的例子是 map 和位置
https://gitlab.kaleidos.net/piweek/betover/betover-mobile/blob/7b9368288743be602f37014f7a49ed4ef943afc1/lib/main.dart

void main() {
  BlocSupervisor.delegate = SimpleBlocDelegate();

  runApp(
    MultiBlocProvider(
      providers: [
        BlocProvider<MapBloc>(
          create: (context) => MapBloc(),
        ),
        BlocProvider<PoisBloc>(
          create: (context) => PoisBloc(
            mapBloc: BlocProvider.of<MapBloc>(context),
          ),
        ),
      ],
      child: App(),
    )
  );
}

class App extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Bet Over',
      theme: appTheme,
      initialRoute: '/',
      routes: {
        '/': (context) =>
          MultiBlocProvider(
            providers: [
              BlocProvider<MapBloc>(
                create: (context) => BlocProvider.of<MapBloc>(context),
              ),
              BlocProvider<PoisBloc>(
                create: (context) => BlocProvider.of<PoisBloc>(context),
              ),
            ],
            child: MapPage(),
          ),
        '/create-poi': (context) =>
          MultiBlocProvider(
            providers: [
              BlocProvider<MapBloc>(
                create: (context) => BlocProvider.of<MapBloc>(context),
              ),
              BlocProvider<PoisBloc>(
                create: (context) => BlocProvider.of<PoisBloc>(context),
              ),
            ],
            child: CreatePoimPage(),
          ),
      }
    );
  }
}

并使用它https://gitlab.kaleidos.net/piweek/betover/betover-mobile/blob/7b9368288743be602f37014f7a49ed4ef943afc1/lib/ui/widgets/map.dart

class _MapState extends State<Map> {
  MapBloc _mapBloc;
  PoisBloc _poisBloc;


@override
  void initState() {
    super.initState();

    _mapBloc = BlocProvider.of<MapBloc>(context);
    _poisBloc = BlocProvider.of<PoisBloc>(context);

...
    List<Marker> _generateMarkers () {
    if (!(_mapBloc.state is MapViewboxChanged && _poisBloc.state is PoisLoaded))
      return [];

关于flutter - 使用 flutter_bloc 构建 Flutter 应用程序的架构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59621809/

相关文章:

linux - 在 Dart 中解码 ANSI 转义序列

android - 任务 ':app:mergeLibDexDebug' 执行失败

flutter - 如何设置 InputDecoration 的 OutlineInputBorder 样式?

dart - 同屏多于一个 float 操作按钮显示黑屏

flutter - StreamBuilder snapshot.hasError 在键盘显示/隐藏 flutter 时显示多次

flutter - Flutter block 监听器内的延迟状态检查

flutter - Flutter Dart 中 EdgeInsetsGeometry 类 EdgeInsets 类之间的区别?

flutter - 如何在 flutter 中管理开关小部件的 native 外观

flutter - 使用 dart 图像包从图像中删除浅色背景

flutter - 为什么我应该使用带有日历的 Bloc 而不是静态 map ?