Снимок не имеет данных в блоке - PullRequest
1 голос
/ 29 марта 2020

Я пытаюсь выучить Blo c с помощью динамического c простого менеджера тем. Я создаю класс с именем theme_bloc:

class DefaultApi {
  final String name;
  final ThemeData theme;

  DefaultApi(this.name, this.theme);
}

class ThemeBloc {
  DefaultApi _defualt;

  ThemeBloc() {}

  final _themeManager = StreamController<DefaultApi>.broadcast();

  Stream<DefaultApi> get themeManager => _themeManager.stream;
  Function(DefaultApi) get changeTheme => _themeManager.sink.add;

  DefaultApi initialTheme() {
    _defualt = DefaultApi("light", ThemeManager.instance.lightTheme);
    return _defualt;

  }

  void dispose() {
    _themeManager.close();
  }
}

для внедрения класса blo c. Я использую провайдера следующим образом:

class ThemeProvider with ChangeNotifier{
 ThemeBloc _bloc;

ThemeProvider(){
  _bloc = ThemeBloc();
}
ThemeBloc get bloc => _bloc;
}

Я использую StringBuilder в main классе. чтобы установить тему следующим образом:

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider.value(
      value: ThemeProvider(),
      child: Consumer<ThemeProvider>(
        builder: (crx, provider, child) {
          return StreamBuilder(
              initialData: provider.bloc.initialTheme(),
              stream: provider.bloc.themeManager,
              builder: (context, AsyncSnapshot<DefaultApi>snapshot) {
                return snapshot.hasData? MaterialApp(
                  title: 'Flutter Demo',
                  theme: snapshot.data.theme,
                  home: HomePage(),
                ):Container();
              });
        },
      ),
    );
  }

На странице HomePage у меня есть переключатель, чтобы изменить тему между светлой и темной темой.

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final bloc = Provider.of<ThemeProvider>(context).bloc;
    return Scaffold(
      appBar: AppBar(
        title: Text("Theme manager"),
      ),
      body: StreamBuilder<DefaultApi>(
          stream: bloc.themeManager,
          builder: (context, snapshot) {
            if (snapshot.hasData) {
              return Switch(
                value: true,
                onChanged: (bool value) {
                },
              );
            } else if (!snapshot.hasData) {
              return Text("loading");
            }
            return Text("!!!!");
          }),
    );
  }

Но после запуска просто загрузка выводится на экран.

enter image description here

Кто-то знает, в чем моя проблема?

1 Ответ

1 голос
/ 29 марта 2020

Ваша проблема решится, если виджет StreamBuilder внутри HomePage имеет initialData. как это:

...
body: StreamBuilder<DefaultApi>(
          initialData: bloc.initialTheme(), // <<< new line 
          stream: bloc.themeManager,
          builder: (context, snapshot) {
...

Этот вход не required. Тем не менее, я не имею ни малейшего понятия, почему это отсутствие вызывает проблему здесь.

Есть несколько более глубоких соображений:

1. Использование ChangeNotifierProvider

Как рекомендует документация , используйте ChangeNotifierProvider вместо ChangeNotifierProvider.value. Очевидно, потому что вы создаете новый экземпляр

...
    return ChangeNotifierProvider(
      create: (_) => ThemeProvider(),
      child: Consumer<ThemeProvider>(
...

2. Предотвращение бесполезного прослушивания

На основании данного руководства , если вы используете провайдера только для вызова действий, вы должны использовать listen: false для предотвращения бесполезных перестроений.

...