首页 文章

使用BLoC处理导航的正确方法

提问于
浏览
6

大家好,我正在使用BLoC for app我正在开发但有些情况我无能为力,就像你登录时激活API调用并等待结果自然我会发送加载状态和显示加载器但是在那之后完成如何处理例如导航到不同的屏幕 . 我现在有类似的东西

typedef void LoginSuccessCallback();
    class LoginBloc(){
    LoginBloc(Api this.api,LoginSuccessCallback loginSuccesCallback){
      _login.switchMap((ev) => api.login(ev.payload.email,ev.payload.password)).listen((_) => loginSuccessCallback);
     }
    }

但我确信有更清洁的方法来处理这个我试图搜索一些类似但却找不到任何东西的样本 .

1 回答

  • 6

    Edit: After a few months with this solution in place, I noticed that there are a few problems with it:

    • Android hardware back button does not work

    • 当您切换"inspect"模式时,该应用会重置 .

    • 无法进行过渡

    • 不保证不显示禁止路线

    所以我不再推荐使用这种方法!


    对于普通的用户启动导航,您根本不需要BLoC模式 . 只需使用 Navigator .

    登录是一种特殊情况 . 遵循BLoC模式,提供 isAuthenticated 流是有意义的:

    abstract class MyBloc {
      Stream<bool> get isAuthenticated;
    }
    

    您的应用可能会有2个不同的命名路由树:一个用于登录用户,另一个用于匿名用户:

    final Map<String, WidgetBuilder> anonymousRoutes = {
      '/': (context) => new LoginScreen(), // default for anon
      '/register': (context) => new RegisterScreen(),
    };
    
    final Map<String, WidgetBuilder> authenticatedRoutes = {
      '/': (context) => new HomeScreen(), // default for logged in
      '/savings': (context) => new SavingsScreen(),
      // ...
    };
    

    通常 Navigator 及其命名路由紧密耦合到 MaterialApp ,但您也可以定义自己在更新 isAuthenticated 流时重建的路径:

    class MyApp extends StatelessWidget {
      const MyApp({Key key, this.bloc}) : super(key: key);
    
      final MyBloc bloc;
    
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          builder: (BuildContext context, Widget child) {
            return StreamBuilder<bool>(
              stream: bloc.isAuthenticated,
              builder: (BuildContext context, AsyncSnapshot<bool> snapshot) {
                if (!snapshot.hasData) {
                  return Text('loading...');
                }
    
                bool isAuthenticated = snapshot.data;
                return _buildNavigator(isAuthenticated);
              },
            );
          },
        );
      }
    }
    
    Navigator _buildNavigator(bool isAuthenticated) {
      // different route tree and different default route depending on auth state
      final routes = isAuthenticated ? authenticatedRoutes : anonymousRoutes;
    
      return Navigator(
        key: new ValueKey(isAuthenticated),
        onGenerateRoute: (RouteSettings settings) {
          final name = settings.name;
          return new MaterialPageRoute(
            builder: routes[name],
            settings: settings,
          );
        },
        onUnknownRoute: (RouteSettings settings) {
          throw Exception('unknown route');
        },
      );
    }
    

    遗憾的是现在(2018-07-14)there are a 2 conflicting asserts在Flutter代码中你必须删除它才能使上面的代码工作(你可以用你的IDE编辑它):

    packages\flutter\lib\src\widgets\app.dart 中的第93和96行

    //assert(navigatorObservers != null),
    //assert(onGenerateRoute != null || navigatorObservers == const <NavigatorObserver>[]),
    

相关问题