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

har*_*k92 12 dart flutter

大家好,我正在使用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);
     }
    }
Run Code Online (Sandbox Code Playgroud)

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

bof*_*mer 9

编辑:在使用此解决方案几个月后,我注意到它有一些问题:

  1. Android硬件后退按钮不起作用
  2. 当您切换"检查"模式时,应用程序将重置.
  3. 没有可能的过渡
  4. 不保证不显示禁止路线

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


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

登录是一个特例.遵循BLoC模式,提供isAuthenticated流是有意义的:

abstract class MyBloc {
  Stream<bool> get isAuthenticated;
}
Run Code Online (Sandbox Code Playgroud)

您的应用程序可能有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(),
  // ...
};
Run Code Online (Sandbox Code Playgroud)

通常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');
    },
  );
}
Run Code Online (Sandbox Code Playgroud)

可悲的是,现在(2018-07-14),Flutter代码中存在2个冲突的断言,您必须删除这些断言才能使上面的代码工作(您可以使用IDE编辑它):

93号线和96号线 packages\flutter\lib\src\widgets\app.dart

//assert(navigatorObservers != null),
//assert(onGenerateRoute != null || navigatorObservers == const <NavigatorObserver>[]),
Run Code Online (Sandbox Code Playgroud)