简体   繁体   English

BlocBuilder() 在 BLoC 产生新的 state 后未更新

[英]BlocBuilder() not being updated after BLoC yielding new state

I am new to the BLoC pattern on flutter and i'm trying to rebuild a messy flutter app using it.我是 flutter 上的 BLoC 模式的新手,我正在尝试使用它重建一个凌乱的 flutter 应用程序。 Currently, I intend to get a list of user's apps and display them with a ListView.builder().目前,我打算获取用户应用程序列表并使用 ListView.builder() 显示它们。 The problem is that whenever the state of my AppsBloc changes, my StatelessWidget doesn't update to show the new state.问题是,每当我的 AppsBloc 的 state 发生变化时,我的 StatelessWidget 不会更新以显示新的 state。 I have tried:我努力了:

  • Using MultiBlocProvider() from the main.dart instead of nesting this appsBloc inside a themeBloc that contains the whole app使用 main.dart 中的 MultiBlocProvider() 而不是将此应用程序块嵌套在包含整个应用程序的主题块中
  • Returning a list instead of a Map, even if my aux method returns a correct map返回列表而不是 Map,即使我的辅助方法返回正确的 map
  • Using a StatefulWidget, using the BlocProvider() only on the ListView...使用 StatefulWidget,仅在 ListView 上使用 BlocProvider()...

I have been reading about this problem on similar projects and the problem might be with the Equatable.我一直在阅读类似项目的这个问题,问题可能出在 Equatable 上。 However, I haven't been able to identify any error on that since I'm also new using Equatable.但是,我无法确定任何错误,因为我也是使用 Equatable 的新手。 I have been debugging the project on VScode with a breakpoint on the yield* line, and it seems to be okay.我一直在用 yield* 行上的断点在 VScode 上调试项目,似乎还可以。 In spite of that the widget doesn't get rebuilt: it keeps displaying the textcorresponding to the InitialState.尽管如此,小部件并没有被重建:它一直显示与 InitialState 相对应的文本。

Moreover, the BLoC doesn't print anything on console even though all the states have an overwritten toString()此外,即使所有状态都覆盖了 toString(),BLoC 也不会在控制台上打印任何内容

These are my 3 BLoC files:这些是我的 3 个 BLoC 文件:

apps_bloc.dart apps_bloc.dart

import 'dart:async';

import 'package:bloc/bloc.dart';
import 'package:device_apps/device_apps.dart';
import 'package:equatable/equatable.dart';

part 'apps_event.dart';
part 'apps_state.dart';

class AppsBloc extends Bloc<AppsEvent, AppsState> {
  @override
  AppsState get initialState => AppsInitial();

  @override
  Stream<AppsState> mapEventToState(AppsEvent event) async* {
    yield AppsLoadInProgress();
    if (event is AppsLoadRequest) {
      yield* _mapAppsLoadSuccessToState();
      }
  }

  Stream<AppsState> _mapAppsLoadSuccessToState() async* {
    try {
      final allApps = await DeviceApps.getInstalledApplications(
          onlyAppsWithLaunchIntent: true, includeSystemApps: true);

      final listaApps = allApps
        ..sort((a, b) =>
            a.appName.toLowerCase().compareTo(b.appName.toLowerCase()));

      final Map<Application, bool> res =
          Map.fromIterable(listaApps, value: (e) => false);

      yield AppsLoadSuccess(res);
    } catch (_) {
      yield AppsLoadFailure();
    }
  }
}

apps_event.dart apps_event.dart

part of 'apps_bloc.dart';

abstract class AppsEvent extends Equatable {
  const AppsEvent();

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

class AppsLoadRequest extends AppsEvent {}

apps_state.dart apps_state.dart

part of 'apps_bloc.dart';

abstract class AppsState extends Equatable {
  const AppsState();

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

class AppsInitial extends AppsState {
  @override
  String toString() => "State: AppInitial";
}

class AppsLoadInProgress extends AppsState {
  @override
  String toString() => "State: AppLoadInProgress";
}

class AppsLoadSuccess extends AppsState {
  final Map<Application, bool> allApps;
  const AppsLoadSuccess(this.allApps);

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

  @override
  String toString() => "State: AppLoadSuccess, ${allApps.length} entries";
}

class AppsLoadFailure extends AppsState {
  @override
  String toString() => "State: AppLoadFailure";
}

main_screen.dart main_screen.dart

class MainScreen extends StatelessWidget {
  const MainScreen({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return TabBarView(
        children: <Widget>[
          HomeScreen(),
          BlocProvider(
            create: (BuildContext context) => AppsBloc(),
            child: AppsScreen(),
          )
          ,
        ],
      );
  }
}

apps_screen.dart apps_screen.dart

class AppsScreen extends StatelessWidget {
  const AppsScreen({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
          body: Container(
          margin: EdgeInsets.fromLTRB(30, 5, 10, 0),
          child: Column(children: <Widget>[
            Row(
              children: <Widget>[
                Text("Apps"),
              ],
            ),
            Row(children: <Widget>[
              Container(
                width: MediaQuery.of(context).size.width - 50,
                height: MediaQuery.of(context).size.height - 150,
                child: BlocBuilder<AppsBloc, AppsState>(
                  builder: (BuildContext context, AppsState state) {
                    if (state is AppsLoadSuccess)
                      return Text("LOADED");
                    else if (state is AppsInitial)
                      return GestureDetector(
                          onTap: () => AppsBloc().add(AppsLoadRequest()),
                          child: Text("INITIAL"));
                    else if (state is AppsLoadInProgress)
                      return Text("LOADING...");
                    else if (state is AppsLoadFailure)
                      return Text("LOADING FAILED");
                  },
                ),
              ),
            ])
          ])),
    );
  }
}

In GestureDetector.onTap() you create a new AppsBloc() , this is wrong.GestureDetector.onTap()你创建一个新的AppsBloc() ,这是错误的。 So, you need:所以,你需要:

apps_screen.dart: apps_screen.dart:

  AppsBloc _appsBloc;

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

    _appsBloc = BlocProvider.of<AppsBloc>(context);
  }

//...

  @override
  Widget build(BuildContext context) {
    //...
    return GestureDetector(
      onTap: () => _appsBloc.add(AppsLoadRequest()),
      child: Text("INITIAL")
    );
    //...
  }

Or you can do the same even without the _appsBloc field:或者,即使没有_appsBloc字段,您也可以这样做:

BlocProvider.of<AppsBloc>(context).add(AppsLoadRequest())

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM