【问题标题】:Flutter bloc state is not emitting or updating. Method mapEventToState is never calledFlutter bloc 状态未发出或更新。从未调用方法 mapEventToState
【发布时间】:2021-12-23 16:24:22
【问题描述】:

以下代码在使用 flutter_bloc 4.0.1 的 null 安全性之前工作,但在 null 安全性迁移之后,状态没有按照 flutter_bloc 7.3.3 的预期更新/发射/广播。

永远不会调用下面的 _reactToStatemapEventToState 方法。我该如何解决?

启动画面

class SplashScreen extends StatefulWidget {
  final Strapper strapper;
  final Service? service;

  SplashScreen(this.strapper, this.service);

  @override
  State<StatefulWidget> createState() => _SplashScreenState();
}

class _SplashScreenState extends State<SplashScreen> {
  SplashBloc? _splashBloc;

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    if (_splashBloc == null) {
      _splashBloc = SplashBloc(widget.strapper, widget.service);

      _splashBloc!.stream.listen(_reactToState);
    }
  }

  @override
  dispose() {
    _splashBloc?.close();
    _splashBloc = null;
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return BlocProvider<SplashBloc>(
      create: (context) => _splashBloc!,
      child: BlocBuilder<SplashBloc, SplashBlocState>(
        builder: (context, state) => Container(
          child: Stack(
            children: <Widget>[
              LogoPanel(
                _showWidgetForState(state),
              ),
            ],
          ),
        ),
      ),
    );
  }

  void _reactToState(SplashBlocState state) {
    if (state is InitializingSplashBlocState) {
      if (widget.logOut) {
        _splashBloc!.add(LogoutSplashBlocEvent());
      } else {
        _splashBloc!.add(CInitializationSplashBlocEvent());
      }
    } else if (state is AuthSuccessSplashBlocState) {
      App.navigateToSomewhere(context, state.isNewUser);
    }
  }

  Widget _showWidgetForState(SplashBlocState state) {
    if (state is InitializingSplashBlocState) {
      return _getProgressIndicator();
    } else if (state is ChooseSomethingSplashBlockState ) {
      return _showSignInWidget();
    }
  }
}

飞溅区

class SplashBloc extends Bloc<SplashBlocEvent, SplashBlocState> {
  final Strapper? strapper;
  final Service? service;

  SplashBloc(this.strapper, this.service) : super(InitializingSplashBlocState());

  @override
  Stream<SplashBlocState> mapEventToState(event) async* {
    if (event is CInitializationSplashBlocEvent) {
      await strapper!.run();
    }
    bool chooseSomething = !service!.hasSomeSelection;

    if (chooseSomething) {
      yield ChooseSomethingSplashBlockState();
    } else if (event is RAuthSplashBlocEvent) {
      yield AuthSplashBlocState();
      var authState = await _run();
      yield authState;
    } 
  }

  Future<SplashBlocState> _run() async {
    // Do something
  }
}

Splash Bloc 活动

abstract class SplashBlocEvent extends Equatable {
  const SplashBlocEvent();

  @override
  List<Object> get props => [];
}

class CInitializationSplashBlocEvent extends SplashBlocEvent {}

class RAuthSplashBlocEvent extends SplashBlocEvent {}

Splash Bloc 状态

abstract class SplashBlocState extends Equatable {
  const SplashBlocState();

  @override
  List<Object> get props => [];
}

class InitializingSplashBlocState extends SplashBlocState {}

class AuthSplashBlocState extends SplashBlocState {}

class ChooseSomethingSplashBlockState extends SplashBlocState {}    

class AuthSuccessSplashBlocState extends SplashBlocState {
  final CurrentUser? user;
  final bool isNewUser;

  AuthSuccessSplashBlocState(this.user, this.isNewUser);
}

【问题讨论】:

  • 见下面我的代码。启动画面应遵循可靠的原则,并使用 bloc 将关注点与界面分离

标签: flutter dart state bloc flutter-bloc


【解决方案1】:

根据documentation

在v6.0.0中,上面的sn -p不输出初始状态,只输出后续的状态变化。以前的行为可以通过以下方式实现:

final bloc = MyBloc();
print(bloc.state);
bloc.listen(print);

所以我在初始屏幕中更改了我的代码,如下所示:

@override
  void didChangeDependencies() {
    super.didChangeDependencies();
    if (_splashBloc == null) {
      _splashBloc = SplashBloc(widget.strapper, widget.service);
      _reactToState(_splashBloc!.state); // Added this line 
      _splashBloc!.stream.listen(_reactToState);
    }
  }

就是这样。有效! _reactToStatemapEventToState 肯定会被调用。

【讨论】:

    【解决方案2】:

    当您使用 Streamcontrollers 时,它大大简化了状态。我构建了一个块代码来管理状态。 materialapp 子项是 splashWidget,其工作是从发出 Time 状态的 bloc 代码中渲染小时、分钟、秒。如果用户单击初始屏幕或经过 5 秒,则初始屏幕将替换为 HomePageWidget。 bloc 代码使用 timerState 事件控制定时器的启动和停止。

    'package:flutter/material.dart';
    import 'bloc_splash.dart';
    import 'main.dart';
    
    class SplashWidget extends StatelessWidget {
      const SplashWidget({Key? key}) : super(key: key);
    
    _redirectToHome(BuildContext context)
    {
      Navigator.pushReplacement(context,MaterialPageRoute(builder:(_)=>MyHomePage(title:"helloWorld")));
    
    }
    String _displayClock(Time ? data)
    {
      String retVal="";
      if (data!=null)
      {
        retVal="Time: ${data.hour} : ${data.minute} : ${data.second}";
      }
      return retVal;
    
    }
      @override
      Widget build(BuildContext context) {
    
        SplashBloc _bloc=SplashBloc();
        _bloc.timerOnChange(StartTimer());
       
        return Scaffold(
    
          body:InkWell(
                  onTap: (){_bloc.timerOnChange(StopTimer());
                  _redirectToHome(context);
                  },
                  child:Container(
                      child: 
              StreamBuilder<TimeState>(
                stream:_bloc.timeStream,
                builder:(context,snapshot)
                {
                  if(snapshot.hasData && (snapshot.data is RedirectState))
                  {
                    return MyHomePage(title:"helloWorld");
                  }
                  return Center(child:Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: [
                    Text("Splash Screen", style:TextStyle(fontSize: 24,fontWeight: FontWeight.bold)),
                    Text(_displayClock(snapshot.data?.time)),
                  ]));
                }
              )
          ))
        );
      }
    }
    

    块代码

    import 'package:equatable/equatable.dart';
    import 'package:flutter/material.dart';
    import 'package:rxdart/rxdart.dart';
    import 'dart:ui';
    import 'dart:async';
    
    abstract class TimerEvent extends Equatable{
      const TimerEvent();
      @override 
      List<Object>get props=>[];
    }
    class StartTimer extends TimerEvent{
      const StartTimer();
    }
    class StopTimer extends TimerEvent{
       const StopTimer();
    }
    
    class Time{
      final int hour;
      final int minute;
      final int second;
      Time(this.hour,this.minute,this.second);
    }
    class TimeState extends Equatable{
      final Time time;
      TimeState(this.time);
      @override
      List<Object> get props=>[time];
    }
    class RedirectState implements TimeState{
      final Time time;
      RedirectState(this.time);
      @override
      List<Object> get props=>[time];
    
      @override
      // TODO: implement stringify
      bool? get stringify => throw UnimplementedError();
    
    }
    
    class TimerState extends Equatable{
     final bool started;
     const TimerState(this.started);
     @override 
     List<Object> get props => [started];
    }
    
    class SplashBloc
    {
       SplashBloc();
       Timer ?_timer;
       var countDown=5;
       Stream<TimeState> get timeStream=> _timeController.stream;
       final _timeController =BehaviorSubject<TimeState>();
       void dispose()
       {
          _timeController.close();
       }
       void _pushTimeOnTheStream(Timer timer)
       {
         DateTime now=DateTime.now();     
          _timeController.sink.add(TimeState(Time(now.hour,now.minute,now.second)));
          this.countDown-=1;
          if (this.countDown==0)
          {
            timerOnChange(StopTimer());
          _timeController.sink.add(RedirectState(Time(0,0,0)));
          }
       }
       void timerOnChange(TimerEvent event) { 
        if (event is StartTimer)
        {
          _timer=Timer.periodic(Duration(seconds: 1),_pushTimeOnTheStream);
        }
        else if(event is StopTimer){
           //_timerController.sink.add(TimerState(false)); 
           _timer?.cancel();
        }
     } 
    }
    

    应用程序

    class MyApp extends StatelessWidget {
      const MyApp({Key? key}) : super(key: key);
    
      // This widget is the root of your application.
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Flutter Demo',
          theme: ThemeData(
            primarySwatch: Colors.blue,
          ),
          home: const SplashWidget(),
        );
      }
    }
    

    【讨论】:

      猜你喜欢
      • 2021-03-19
      • 2020-10-10
      • 2020-07-05
      • 2021-05-20
      • 2021-08-02
      • 2020-08-03
      • 1970-01-01
      • 2020-09-03
      • 2021-01-06
      相关资源
      最近更新 更多