首页 > 解决方案 > 热重载不起作用,需要热重启Flutter

问题描述

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

我认为我用 redux 管理状态的方式,阻止我用 hot reload 重新加载应用程序,我解释:如果我有一个带背景的脚手架,从主题数据,如果主题模式当前是暗的,以及背景颜色是颜色(0xFF1F1F1F)(黑色阴影),我将其更改为颜色(0xFFFFFFFF)(纯白色),然后我使用热重载,它不起作用,我需要用热重启重新启动整个应用程序到看到变化。我的主题管理器也是如此,我使用单选按钮来管理它,如果我将主题更改为浅色或深色,它工作正常。

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

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 的那个)中,如果我稍后使用 Theme.of 相同的颜色,themeData 值也是正确的(上下文)(就像我在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);

标签: androidflutterdartredux

解决方案


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

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

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

所以来自 Flutter 文档

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


推荐阅读