状态变化时的 Bloc 导航

Bloc navigation on state change

我真的是 flutter bloc 的新手,我在 bloc 实现方面遇到了一些问题,我正在尝试在启动画面小部件中的状态发生变化后进行导航。

在状态更新为 InitSuccess 之后,它应该导航到 LoginScreen,但是这种导航发生了很多次。

我无法理解在状态更改为 InitSuccess 之后该做什么。

启动画面

class SplashScreen extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => _SplashScreenState();
}

class _SplashScreenState extends State<SplashScreen> {
  SplashBloc _splashBloc;
  final _scaffoldKey = GlobalKey<ScaffoldState>();

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

  @override
  void dispose() {
    _splashBloc.dispose();
    super.dispose();
  }

  void _init() {
    Future.delayed(Duration.zero, () {
      checkDeviceConnection(context);
      BlocSupervisor().delegate = SplashBlocDelegate();
      final bool isIOS = Theme.of(context).platform == TargetPlatform.iOS;
      _splashBloc = SplashBloc(
        firebaseService: FirebaseService(context),
        authService: AuthService(context),
        devicesService: DevicesService(context),
      );
      _splashBloc.dispatch(SplashInitEvent(isIOS: isIOS));
    });

@override
  Widget build(BuildContext context) {
    SystemChrome.setEnabledSystemUIOverlays([]);
    return BlocBuilder<SplashEvent, SplashState>(
      bloc: _splashBloc,
      builder: (
        BuildContext context,
        SplashState state,
      ) {
        if (state is InitFailure) {
          Future.delayed(Duration.zero, () {
            showWarningSnackBar(_scaffoldKey, state.error);
          });
        }

        if (state is InitSuccess) {
          Future.delayed(Duration.zero, () {
            Navigator.push(
              context,
              MaterialPageRoute(
                builder: (context) => LoginScreen(),
              ),
            );
          });
        }

        return Scaffold(
          key: _scaffoldKey,
          body: Container(
            decoration: appScreenGradient,
            alignment: Alignment.center,
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                Image.asset(
                  "assets/images/splash_screen/logo_splash.png",
                  width: 172.88,
                  height: 144.55,
                  fit: BoxFit.contain,
                ),
                SizedBox(
                  height: 20.0,
                ),
                LoadingSpinner(
                  spinnerColor: Theme.of(context).primaryColorLight,
                ),
              ],
            ),
          ),
        );
      },
    );
  }

飞溅集团

class SplashBloc extends Bloc<SplashEvent, SplashState> {
  final FirebaseService firebaseService;
  final DevicesService devicesService;
  final AuthService authService;
  final UserPreferences _userPreferences = UserPreferences();

  SplashBloc({
    @required this.firebaseService,
    @required this.devicesService,
    @required this.authService,
  });

  @override
  Stream<SplashEvent> transform(Stream<SplashEvent> events) {
    return (events as Observable<SplashEvent>).debounce(
        Duration(milliseconds: 500));
  }

  @override
  get initialState => SplashInitial();

  @override
  Stream<SplashState> mapEventToState(currentState, event) async* {
    if (event is SplashInitEvent) {
      if (currentState is SplashInitial) {
        yield InitLoading();

        try {
          firebaseService.togglePerformanceCollection(true);
          firebaseService.firebaseCloudMessagingListeners();

          String firebaseToken = await firebaseService
              .getFirebaseMessagingToken();
          bool isRegistered =
              await _userPreferences.getIsDeviceRegistered() ?? false;

          if (!isRegistered) {
            final String platform = event.isIOS ? 'IOS' : 'Android';
            final deviceInfo = await devicesService.getDeviceInfo(platform);
            isRegistered = await devicesService.register(
              deviceToken: firebaseToken,
              deviceInfo: deviceInfo,
            );
            if (isRegistered) {
              _userPreferences.setIsDeviceRegistered(true);
            }
          }

          yield InitSuccess();
        } catch (e) {
          yield InitFailure(error: e.toString());
        }
      }
    }

    if (event is SplashInitialEvent) {
      yield SplashInitial();
    }
  }
}

我找到了以下解决方案:

if (state is LoggedIn) {
  WidgetsBinding.instance.addPostFrameCallback((_) { 
    // Navigation
  });
}

我用这个 addPostFrame 回调包装了我的导航以延迟它的出现。