Flutter Bloc - Flutter Bloc 状态未更新

Posted

技术标签:

【中文标题】Flutter Bloc - Flutter Bloc 状态未更新【英文标题】:Flutter Bloc - Flutter Bloc state not updating 【发布时间】:2021-03-19 05:30:32 【问题描述】:

我刚刚开始使用颤振集团。 我尝试制作状态,但它总是进入初始状态。有什么解决办法?

集团

class VisiMisiBloc extends Bloc<VisiMisiEvent, VisiMisiState> 
  VisiMisiBloc(this.visiMisiRepository) : super(VisiMisiInitial());

  final VisiMisiRepository visiMisiRepository;
  
  @override
  Stream<VisiMisiState> mapEventToState(VisiMisiEvent event) async* 
    if (event is GetVisiMisiList) 
      yield* _getVisiMisi(event, state);
    
  

  Stream<VisiMisiState> _getVisiMisi(VisiMisiEvent event, VisiMisiState state) async* 
    yield VisiMisiLoading();
    try 
      ResponseModel<VisiMisiModel> response = await visiMisiRepository.getVisiMisi();
      print(response);

      if (response.statusCode == 0) 
        int insertedId = await visiMisiRepository.insertVisiMisi(response.data);
        print(insertedId);
        List<VisiMisiModel> visiMisiList = await visiMisiRepository.getAllVisiMisi();
        yield VisiMisiLoaded(visiMisiList);

       else 
        yield VisiMisiError(response.errorMessage);
      
     on Exception catch (e) 
      yield VisiMisiError(e.toString());
    
  

状态

part of 'visi_misi_bloc.dart';

abstract class VisiMisiState extends Equatable 
  const VisiMisiState();


class VisiMisiInitial extends VisiMisiState 
  const VisiMisiInitial();
  @override
  List<Object>get props => [];



class VisiMisiLoading extends VisiMisiState 
  const VisiMisiLoading();
  @override
  List<Object>get props => [];


class VisiMisiLoaded extends VisiMisiState 
  final List<VisiMisiModel> visiMisiModel;
  const VisiMisiLoaded(this.visiMisiModel);
  @override
  List<Object> get props => [visiMisiModel];


class VisiMisiError extends VisiMisiState 
  final String message;
  const VisiMisiError(this.message);
  @override
  List<Object>get props => [message];

活动

part of 'visi_misi_bloc.dart';

abstract class VisiMisiEvent extends Equatable
  const VisiMisiEvent();


class GetVisiMisiList extends VisiMisiEvent 
  @override
  List<Object> get props => [];

存储库

abstract class VisiMisiRepository 
  Future<int> insertVisiMisi(VisiMisiModel todo);
  Future<ResponseModel<VisiMisiModel>> getVisiMisi();
  Future<List<VisiMisiModel>> getAllVisiMisi();

存储库实现

class VisiMisiRepositoryImpl extends VisiMisiRepository 
  final NetworkInfoImpl networkInfo;
  final RemoteDataSource remoteDatasource;
  final VisiMisiDao dao;

  VisiMisiRepositoryImpl(this.networkInfo, this.remoteDatasource, this.dao);

  @override
  Future<ResponseModel<VisiMisiModel>> getVisiMisi() 
    return remoteDatasource.visiMisi();
  

  @override
  Future<int> insertVisiMisi(VisiMisiModel todo) 
    return dao.upsert(todo);
  

  @override
  Future<List<VisiMisiModel>> getAllVisiMisi() 
    return dao.getAll(userTABLE, VisiMisiModel.fromJson);
  

远程数据源

Future<ResponseModel<VisiMisiModel>> visiMisi() async 
    SharedPreferences prefs = await SharedPreferences.getInstance();
    String auth_token = prefs.getString("auth_token");
    try 
      final response = await httpClient.get(ServiceUrl.visiMisi, auth_token);

      if(response.statusCode != 200)
        throw new Exception('Error getting visi misi');
      

      return ResponseModel<VisiMisiModel>.fromJson(response, VisiMisiModel.fromJson);
    catch(e)
      print(e);
    
  

查看

class VisiMisiPage extends StatefulWidget 
  @override
  _VisiMisiPageState createState() => _VisiMisiPageState();


class _VisiMisiPageState extends State<VisiMisiPage> 
  VisiMisiRepository repository;

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

  @override
  Widget build(BuildContext context) 
    return SafeArea(
      child: Scaffold(
          backgroundColor: AppColor.white,
          appBar: AppBar(
            title: Text("VISI & MISI", style: TextStyle(fontSize: 16, color: AppColor.deepCerulean),),
            backgroundColor: Colors.white,
            elevation: 0,
            automaticallyImplyLeading: false,
            brightness: Brightness.light,
            leading: IconButton(
              icon: new Icon(Icons.arrow_back, color: AppColor.deepCerulean,),
              onPressed: () => Navigator.of(context).pop(),
            ),
          ),
          body: BlocProvider<VisiMisiBloc>(
            create: (_) => VisiMisiBloc(repository),
            child: BlocBuilder<VisiMisiBloc, VisiMisiState>(
                  builder: (context, state) 
                    if (state is VisiMisiInitial) 
                      //BlocProvider.of<VisiMisiBloc>(context).add(GetVisiMisiList());
                      return Center(child: Text(state.toString()),);
                     else if (state is VisiMisiLoading) 
                      return Center(child: CircularProgressIndicator(),);
                     else if (state is VisiMisiLoaded) 
                      return SingleChildScrollView(
                        child: Container(
                          child: Column(
                            mainAxisAlignment: MainAxisAlignment.start,
                            crossAxisAlignment: CrossAxisAlignment.start,
                            children: [
                              _visiWidget(context, state),
                              SizedBox(height: 20,),
                              _misiWidget(context),
                              SizedBox(height: 30,),
                              _footerWidget(context)
                            ],
                          ),
                        ),
                      );
                     else if (state is VisiMisiError) 
                      return Center(child: Text(state.message),);
                    
                  
              )
            ),
          )
    );
  

  void _onWidgetDidBuild(Function callback) 
    WidgetsBinding.instance.addPostFrameCallback((_) 
      callback();
    );
  

我得到一个未处理的异常:未处理的错误 NoSuchMethodError:方法 'getVisiMisi' 在 null 上被调用。

在视图中,状态显示在 VisiMisiInitial 中,并且不想更新到 VisiMisiLoading

【问题讨论】:

【参考方案1】:

我分析了你的代码,发现了2个错误:

1st.您刚刚创建了 VisiMisiRepository 的实例,但尚未初始化。你正在调用他们的方法,这就是为什么你会收到错误Unhandled error NoSuchMethodError: The method 'getVisiMisi' was called on null.

第二次。您刚刚在传递的存储库实例中初始化了您的 bloc,并且还没有执行任何 bloc 事件。这就是代码一直显示初始状态的原因。

您可能已经得到了答案。 如果没有,请从这里寻求帮助,它一定会对您有所帮助:

替换这个:

create: (_) =&gt; VisiMisiBloc(repository),

用这个:

create: (_) =&gt; VisiMisiBloc(VisiMisiRepository())..add(GetVisiMisiList()),

在您的小部件树中:

body: BlocProvider<VisiMisiBloc>(
            create: (_) => VisiMisiBloc(VisiMisiRepository())..add(GetVisiMisiList()), //initialising bloc within repository and hit event as well.
           
            child: BlocBuilder<VisiMisiBloc, VisiMisiState>(
                  builder: (context, state) 
                    if (state is VisiMisiInitial) 
                  
                      return Center(child: Text(state.toString()),);
                     else if (state is VisiMisiError) 
                      return Center(child: Text(state.message),);
                     else if (state is VisiMisiLoaded) 
                      return SingleChildScrollView(
                        child:  Container(
                          child: Column(
                            mainAxisAlignment: MainAxisAlignment.start,
                            crossAxisAlignment: CrossAxisAlignment.start,
                            children: [
                              _visiWidget(context, state),
                              SizedBox(height: 20,),
                              _misiWidget(context),
                              SizedBox(height: 30,),
                              _footerWidget(context)
                            ],
                          ),
                        ),
                      );
                     

                    return  Center(child: CircularProgressIndicator(),);
                  
              )
            ),

这个答案也将解决Unhandled error NoSuchMethodError: The method 'getVisiMisi' was called on null 错误。

【讨论】:

【参考方案2】:

要初始化存储库,您应该使用 RepositoryProvider。

例如,类似的东西

class MyApp extends StatelessWidget 
  @override
  Widget build(BuildContext context) 
    return MultiRepositoryProvider(
        providers: [
          RepositoryProvider<UserRepository>(
            create: (context) => UserRepository(),
          ),
        ],
        child: MultiBlocProvider(
            providers: [
              BlocProvider<LoginBloc>(
                create: (context) => LoginBloc(context.read<UserRepository>()),
              ),
            ],
            child: Widget()));
  

然后会自动初始化

【讨论】:

【参考方案3】:

尝试像这样初始化存储库:

class _VisiMisiPageState extends State<VisiMisiPage> 
  VisiMisiRepository repository;

  @override
  void initState()
    super.initState();
    repository = VisiMisiRepositoryImpl( parameters here ); // add this one
  

【讨论】:

以上是关于Flutter Bloc - Flutter Bloc 状态未更新的主要内容,如果未能解决你的问题,请参考以下文章

使用带有flutter_bloc的Equatable类

没有 BLoC 的 Flutter 状态管理

flutter_bloc 库中的存储库提供程序在推送新路由时不提供存储库

谁能说出 Flutter 中“flutter_bloc”和“bloc”包的区别

Flutter Bloc - Flutter Bloc 状态未更新

Flutter:BLoC 包 - bloc 提供者