热重载不起作用,需要热重启 Flutter

时间:2021-07-12 11:56:29

标签: android flutter dart redux

我正在制作一个应用,它有一个主题管理器、浅色模式、深色模式和系统模式。

我认为我用 redux 管理状态的方式,阻止了我用热重载来重载应用程序,我解释说: 如果我有一个带背景的脚手架,从themedata,如果thememode当前是暗的,并且背景颜色是Color(0xFF1F1F1F)(黑色阴影),我将其更改为Color(0xFFFFFFFF)(纯白色),然后我使用热重载,它不起作用,我需要通过热重启重新启动整个应用程序以查看更改。 与我的主题管理器一样,我使用单选按钮来管理它,如果我将主题更改为浅色或深色,则效果很好。

如果我将模式更改为系统,它可以正常工作,但是在打开应用程序的系统主题模式下,如果我更改手机的系统主题模式,则不起作用。在这种情况下 StoreProvider.dispatch 不起作用,store.dispatch 也不工作,我必须使用热重启。 这里是可能导致问题的代码。 main.dart:

import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
import 'package:flutter/services.dart';

import 'package:async_redux/async_redux.dart';
import 'package:hive/hive.dart';

import 'package:app_name/Redux/States/AppState.dart';
import 'package:app_name/UI/Screens/AppHome.dart';
import 'package:app_name/Utilities/Themes.dart';
import 'package:app_name/Utilities/functions.dart';
import 'package:app_name/Utilities/extensions.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();

  Box box = await initHive();
  SettingsState settingsState = SettingsState(
    themeMode: box.get("theme").toString().themeModeFromString,
  );

  Store<AppState> store = Store(
    initialState: AppState(settings: settingsState),
  );
  runApp(App(store: store));
}

class App extends StatelessWidget {
  final Store<AppState> store;

  App({
    required this.store,
  });

  Widget build(BuildContext context) {
    return StoreProvider<AppState>(
      store: store,
      child: StoreConnector<AppState, SettingsState>(
        converter: (Store<AppState> store) => store.state.settings,
        builder: (BuildContext context, SettingsState settings) {
         
          return MaterialApp(
            debugShowCheckedModeBanner: false,
            title: 'Carleo',
            theme: lightTheme,
            darkTheme: darkTheme,
            themeMode: settings.themeMode,
            home: Focus(
              onFocusChange: (hasFocus) =>
                  SystemChrome.setEnabledSystemUIOverlays([]),
              autofocus: true,
              descendantsAreFocusable: true,
              child: AppHome(),
            ),
          );
        },
      ),
    );
  }
}

这里是文件 AppHome.dart:

import 'package:app_name/UI/Widgets/Radio%20buttons.dart';
import 'package:flutter/material.dart';

import 'package:carleo/UI/Screens/SelectAccess.dart';
import 'package:carleo/UI/Screens/Home.dart';
import 'package:carleo/UI/Widgets/CircularIndicator.dart';
import 'package:carleo/Utilities/Database Utilities.dart';
import 'package:app_name/Utilities/Themes.dart';

class AppHome extends StatelessWidget {
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: ThemeGetter.primary(context),
      body: ThemeRadioButton(),
    );
  }
}

这里是 Radio Buttons.dart:

import 'package:flutter/material.dart';

import 'package:async_redux/async_redux.dart';

import 'package:app_name/Redux/States/AppState.dart';
import 'package:app_name/Redux/Actions/Actions.dart';

class ThemeRadioButton extends StatelessWidget {
  Widget build(BuildContext context) {
    return StoreConnector<AppState, SettingsState>(
      converter: (Store<AppState> store) => store.state.settings,
      builder: (BuildContext context, SettingsState settings) {
        return Wrap(
          children: [
            ListTile(
              leading: Radio<ThemeMode>(
                value: ThemeMode.light,
                fillColor: MaterialStateProperty.all(Colors.black),
                groupValue: settings.themeMode,
                onChanged: (ThemeMode? mode) {
                  StoreProvider.dispatch<AppState>(
                    context,
                    ThemeChanger(
                      payload: mode ?? ThemeMode.light,
                    ),
                  );
                },
              ),
              title: Text("Light"),
            ),
            ListTile(
              leading: Radio<ThemeMode>(
                value: ThemeMode.dark,
                fillColor: MaterialStateProperty.all(Colors.black),
                groupValue: settings.themeMode,
                onChanged: (ThemeMode? mode) {
                  StoreProvider.dispatch<AppState>(
                    context,
                    ThemeChanger(
                      payload: mode ?? ThemeMode.dark,
                    ),
                  );
                },
              ),
              title: Text("Dark"),
            ),
            ListTile(
              leading: Radio<ThemeMode>(
                value: ThemeMode.system,
                fillColor: MaterialStateProperty.all(Colors.black),
                groupValue: settings.themeMode,
                onChanged: (ThemeMode? mode) {
                  StoreProvider.dispatch<AppState>(
                    context,
                    ThemeChanger(
                      payload: mode ?? ThemeMode.system,
                    ),
                  );
                },
              ),
              title: Text("System"),
            ),
          ],
        );
      },
    );
  }
}

这里有任何其他可以帮助的东西:

ThemeData darkTheme = ThemeData(
  backgroundColor: Color(0xFF1F1F1F),
  accentColor: Color(0xFF101217),
  primaryColor: Color(0xFFFFFFFF),
  buttonColor: Color(0xFF0D47A1),
  brightness: Brightness.dark,
);
ThemeData lightTheme = ThemeData(
  backgroundColor: Color(0xFFFFFFFF),
  accentColor: Color(0xFFFFFFFF),
  brightness: Brightness.light,
);

class ThemeGetter {
  static Color primary(BuildContext context) {
    return Theme.of(context).backgroundColor;
  }

  static Color accent(BuildContext context) {
    return Theme.of(context).accentColor;
  }

  static Color contrast(BuildContext context) {
    return Theme.of(context).primaryColor;
  }

  static Color secondary(BuildContext context) {
    return Theme.of(context).buttonColor;
  }
}

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart' show ThemeMode;

extension StringEnumExtension on String {
  ThemeMode get themeModeFromString => ThemeMode.values.firstWhere(
        (e) => describeEnum(e) == this,
        orElse: () => ThemeMode.system,
      );
}

extension ThemeModeExtensions on ThemeMode {
  String get name => describeEnum(this);
}

import 'package:flutter/material.dart' show ThemeMode;

class AppState {
  final SettingsState settings;

  AppState({SettingsState? settings})
      : this.settings = settings ?? SettingsState();

  AppState.copy({
    required AppState state,
  }) : this.settings = state.settings;

  AppState copyWith({int? counter, SettingsState? settings}) => AppState(
        settings: settings ?? this.settings,
      );

  @override
  operator ==(Object another) =>
      identical(this, another) ||
      (another is AppState && this.settings == another.settings);

  @override
  int get hashCode => super.hashCode;
}

class SettingsState {
  final ThemeMode themeMode;

  SettingsState({
    ThemeMode? themeMode,
  }) : this.themeMode = themeMode ?? ThemeMode.system;

  SettingsState.copy({
    required SettingsState state,
  }) : this.themeMode = state.themeMode;

  SettingsState copyWith({ThemeMode? themeMode, ThemeMode? radioValue}) =>
      SettingsState(
        themeMode: themeMode ?? this.themeMode,
      );

  @override
  operator ==(Object another) =>
      identical(this, another) &&
      (another is SettingsState && another.themeMode == this.themeMode);

  @override
  int get hashCode => super.hashCode;
}

import 'package:async_redux/async_redux.dart';
import 'package:flutter/material.dart' show ThemeMode;
import 'package:hive/hive.dart';

import 'package:carleo/Redux/States/AppState.dart';
import 'package:carleo/Utilities/extensions.dart';

class ThemeChanger extends ReduxAction<AppState> {
  final ThemeMode payload;
  ThemeChanger({
    required this.payload,
  });
  @override
  Future<AppState> reduce() async {
    Box box = await Hive.openBox("Settings");
    box.put("theme", payload.name);
    return state.copyWith(
      settings: state.settings.copyWith(
        themeMode: payload,
      ),
    );
  }
}


将接受任何帮助。并提前致谢。

编辑: 我注意到,即使 settings.themeMode 是 ThemeMode.system,并且在商店连接器(构建 MaterialApp 的那个)中,themeData 值是正确的,如果我稍后使用与 Theme.of(context )(就像我在AppHome的脚手架后台做的一样),打印出来的颜色不是正确的,是上次热重启的颜色。 我把它放在 StoreConnector 构建器中是为了注意:

Brightness brightness =
              SchedulerBinding.instance!.window.platformBrightness;
bool darkModeOn = brightness == Brightness.dark;
print(settings.themeMode);
switch (settings.themeMode) {
    case ThemeMode.light:
        print(lightTheme.primaryColor);
        break;
    case ThemeMode.dark:
        print(darkTheme.primaryColor);
        break;
    case ThemeMode.system:
        if (darkModeOn)
            print(darkTheme.primaryColor);
        else
            print(lightTheme.primaryColor);
}

并简单地使用此代码来注意不同小部件中的颜色不同:

print(Theme.of(context).backgroundColor);

2 个答案:

答案 0 :(得分:1)

应用的 main()initState() 方法的某些代码更改可能在热重新加载时在刷新后的 UI 中不可见。

<块引用>

作为一般规则,如果修改后的代码在根的下游 小部件的 build() 方法,然后热重载按预期运行。然而, 如果修改后的代码不会因为重建而重新执行 小部件树,那么在热重载后您将看不到它的效果。

这可能是热重载后主题数据更改未反映的原因,因为它是在应用程序的 main() 中定义的。

因此来自 Flutter 文档

<块引用>

热重载将代码更改加载到虚拟机中并重新构建小部件 树,保留应用程序状态;它不会重新运行 main()initState()

答案 1 :(得分:0)

根据 flutter 文档 - 自 21 年 7 月 16 日起,flutter web 未启用热重载

Flutter hot reload doc

起亚卡哈,

迈克·史密斯