我有一个编程时刻,我觉得我快疯了,所以希望有人可以帮助我。
我有一个 Flutter 应用程序,它使用 Hive 在运行之间存储数据。 当应用最初启动时,它会打开一个框并检索一些信息,以便为 MaterialApp 设置保存的主题。 然后,它会为应用构建主页并检索一系列其他选项。 这运行良好(我的手机上有一个运行完美的版本),但由于某种原因它已停止工作。
当应用执行时,初始 MyApp 会声明 Hive 框已打开,但其中没有值。 对于调用选项类以检索选项数据,情况就是如此。 在那次调用之后,盒子突然有了值,我能够检索和打印出密钥。 当应用随后生成主页时,它会声明该框已打开,并且具有值,并且能够从选项类中检索选项数据。 以前,我在第一次读取数据以提取主题时没有问题。 我已经在下面发布了代码的相关部分,其中包含运行的打印输出。
我正在 Web 上运行该应用程序,并在移动模拟器上运行它。 它以前在两个平台上都运行良好,但现在无法在 Web 平台上工作。 它似乎在移动模拟器上运行良好。
该应用程序使用以下版本:
Flutter 2.10.4 • channel stable • https://github.com/flutter/flutter.git
Framework • revision c860cba910 (6 days ago) • 2022-03-25 00:23:12 -0500
Engine • revision 57d3bac3dd
Tools • Dart 2.16.2 • DevTools 2.9.2
pubspec.yaml dependencies:
hive: ^2.0.6
hive_flutter: ^1.1.0
我今天已升级到最新版本的 Flutter,看看是否可以解决问题。 我在以前的稳定版本中遇到了同样的问题。
我已经更新到 hive 2.1.0 并获得相同的问题/输出。
我还尝试使用 Dart 2.10.0 将 Flutter 降级到 2.16.0,我知道它工作正常,但这并没有解决问题。
主飞镖
import 'package:flutter/material.dart';
import 'package:hive_flutter/hive_flutter.dart';
import 'package:flex_color_scheme/flex_color_scheme.dart';
import 'package:responsive_sizer/responsive_sizer.dart';
import 'package:lettercloud/data/colours.dart';
import 'package:lettercloud/options/option_page.dart';
const String _boxName = 'lettercloud';
void main() async {
await Hive.initFlutter();
Hive
..registerAdapter(CellAdapter())
..registerAdapter(ThemeModeOptionAdapter());
await Hive.openBox(_boxName);
runApp(MyApp());
}
class MyApp extends StatelessWidget {
MyApp({Key? key}) : super(key: key);
final Box _box = Hive.box(_boxName); // Object for hive data access
final Options _options = Options();
final Colours _colours = Colours();
late bool _firstRun = true; // Flag to only read Hive options on first run
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
print('build() Before first run. Extracting box keys. Attempt 1...');
for (String key in _box.keys) {
print('box keys: $key');
}
if (_firstRun) {
print(
'First run. Hive box is open: ${_box.isOpen} Box has values: ${_box.isNotEmpty}');
_options.setHiveBox(_box); // Pass hive object and retrieve options
_firstRun = false;
}
print('');
print('build() After first run. Extracting box keys. Attempt 2...');
for (String key in _box.keys) {
print('box keys: $key');
}
return AnimatedBuilder(
animation: _options.getThemeNotifier(),
builder: (context, child) {
return MaterialApp(
title: 'Lettercloud',
theme: FlexThemeData.light(scheme: FlexScheme.jungle),
darkTheme: FlexThemeData.dark(scheme: FlexScheme.jungle),
themeMode: _options.getThemeMode(),
home: ResponsiveSizer(
builder: (context, orientation, screenType) {
return const MyPage(title: 'Lettercloud Anagram Helper');
},
),
);
});
}
}
class MyPage extends StatefulWidget {
const MyPage({Key? key, required this.title}) : super(key: key);
final String title;
@override
State<MyPage> createState() => MyPageState();
}
class MyPageState extends State<MyPage> {
final Options _options = Options();
late final Box _box; // Object for hive data access
late Widget _displayGrid;
@override
void initState() {
super.initState();
print('Doing init MyPageState');
_box = Hive.box(_boxName);
_options.setHiveBox(_box); // Pass hive object and retrieve options
_setGrid(_options.getGridType());
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Lettercloud'),
),
resizeToAvoidBottomInset: false, // Overlay on-screen keyboard
body: SafeArea(
child: _displayGrid,
),
);
}
// Set the grid to display based on the grid type option
void _setGrid(GridType type) {
_displayGrid = _options.getGridType() == GridType.square
? GridSquare(box: _box, options: _options, update: updateGrid)
: GridDiamond(box: _box, options: _options, update: updateGrid);
}
// Callback to set the grid type if the option changes
void updateGrid(GridType type) {
setState(() {
_setGrid(type);
});
}
}
选项.dart
import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart' show kIsWeb;
import 'package:hive_flutter/hive_flutter.dart';
class Options {
bool _lightMode = true; // Use light colours, or dark
static const String _lightModeName = 'lightMode';
bool _showGrid = true; // Show grid around tiles, or not
static const String _showGridName = 'showGrid';
bool _firstEdit =
true; // Flag to show edit on first start, doesn't need saving
bool _editOnStart = false; // Show edit at startup, or not
static const String _editOnStartName = 'editOnStart';
CharType _charType = CharType.mixed; // Type of letters to show
static const String _charTypeName = 'charType';
ThemeModeOption _themeMode = ThemeModeOption()..setMode(ThemeMode.light);
static const String _themeModeName = 'themeMode';
late Box _box; // Hive object
late final double _tabletF; // Reduction factor for tablet displays
late GridType _gridType = GridType.square;
static const String _gridTypeName = 'gridType';
late GridType _savedGridType = _gridType;
static const String _savedGridTypeName = 'savedGridType';
// last page name - used to control text entry on startup
String _lastPage = PageName.main.toString();
static const String _lastPageName = 'lastPageName';
// Flag to show if the grid type has change. Used to prevent 'show on start'
// triggering the text entry box after the grid layout has been changed by the user
bool _backFromOptionsPage = false;
final String _backFromOptionsPageName = 'fromOptions';
///
/// Hive management methods and global options setting
///
void setHiveBox(Box b) {
_box = b; // Pass the hive management object
print(
'Options hive box. Box is open: ${_box.isOpen} Box has values: ${_box.isNotEmpty}.');
// Set screen size factor for web vs tablet
if (kIsWeb) {
_tabletF = 0.4; // Factor components by 0.4 for web
} else {
_tabletF = 0.6; // Factor components by 0.6 for tablets
}
// Retrieve any option data values
if (_box.get(_lightModeName) != null) {
_lightMode = _box.get(_lightModeName);
} else {
print('Cannot find $_lightModeName');
_box.put(_lightModeName, _lightMode);
}
if (_box.get(_showGridName) != null) {
_showGrid = _box.get(_showGridName);
} else {
_box.put(_showGridName, _showGrid);
}
if (_box.get(_editOnStartName) != null) {
_editOnStart = _box.get(_editOnStartName);
} else {
_box.put(_editOnStartName, _editOnStart);
}
if (_box.get(_charTypeName) != null) {
String temp = _box.get(_charTypeName);
_charType = getCharEnum(temp);
} else {
_box.put(_charTypeName, _charType.toString());
}
if (_box.get(_themeModeName) != null) {
_themeMode = _box.get(_themeModeName);
} else {
_box.put(_themeModeName, _themeMode);
}
if (_box.get(_gridTypeName) != null) {
String temp = _box.get(_gridTypeName);
_gridType = getGridEnum(temp);
} else {
_box.put(_gridTypeName, _gridType.toString());
}
if (_box.get(_savedGridTypeName) != null) {
String temp = _box.get(_savedGridTypeName);
_savedGridType = getGridEnum(temp);
} else {
_box.put(_savedGridTypeName, _savedGridType.toString());
}
if (_box.get(_backFromOptionsPageName) != null) {
_box.put(_backFromOptionsPageName, _backFromOptionsPage);
} else {
_box.put(_backFromOptionsPageName, _backFromOptionsPage);
}
// Load last page value or reset if doesn't exit
if (_box.get(_lastPageName) != null) {
_box.put(_lastPageName, _lastPage);
} else {
_box.put(_lastPageName, _lastPage);
}
_box.flush(); // Make sure everything is written to the disk
}
}
命令行输出:
flutter run -d chrome --web-renderer html --web-port 5555
Launching libmain.dart on Chrome in debug mode...
Waiting for connection from debug service on Chrome... 18.6s
This app is linked to the debug service: ws://127.0.0.1:54752/JAXqfQgauf4=/ws
Debug service listening on ws://127.0.0.1:54752/JAXqfQgauf4=/ws
Running with sound null safety
To hot restart changes while running, press "r" or "R".
For a more detailed help message, press "h". To quit, press "q".
An Observatory debugger and profiler on Chrome is available at: http://127.0.0.1:54752/JAXqfQgauf4=
The Flutter DevTools debugger and profiler on Chrome is available at:
http://127.0.0.1:9101?uri=http://127.0.0.1:54752/JAXqfQgauf4=
build() Before first run. Extracting box keys. Attempt 1...
First run. Hive box is open: true Box has values: false
Options hive box. Box is open: true Box has values: false.
Cannot find lightMode
build() After first run. Extracting box keys. Attempt 2...
box keys: charType
box keys: editOnStart
box keys: fromOptions
box keys: gridType
box keys: lastPageName
box keys: lightMode
box keys: savedGridType
box keys: showGrid
box keys: themeMode
Doing init MyPageState
Options hive box. Box is open: true Box has values: true.
Application finished.
更新#1自最初发布以来,我尝试删除该框并重新运行该应用程序,以防这是由损坏的文件引起的。 这没有任何区别。
我还尝试在 openBox() 命令中添加一个 .then,以防这是另一个异步编程问题,但这也没有区别,即
await Hive.openBox(_boxName).then((value) {
print('value is $value');
runApp(MyApp());
});
更新 #2所以,我花了一段时间才解决这个问题,但如果它们尚不存在,我会在第一次运行时创建我的框值(以解决应用程序首次运行的用例)。 如果我删除 setHiveBox() 方法中的所有 put 语句,那么我就会一直遇到问题。 换句话说,在我的 Options 类在应用运行时创建这些值之前,框中没有值。 这表明应用程序未将数据保存到磁盘。 我已经将main.dart和options.dart与最近已知的工作版本进行了比较,没有看到任何明显的差异。 什么会阻止应用程序将数据保存到磁盘? 请注意,我已经测试了我开发的另一个使用 Hive 的应用程序,并且它继续完美运行。它使用与此应用程序相同的Hive版本。
我通过在项目上执行flutter clean
,删除颤振安装(从磁盘中完全删除安装文件夹),下载并重新安装Flutter,然后在项目文件夹上执行flutter pub get
来解决此问题。
我之前尝试过flutter clean
并自行flutter pub get
,但这并没有解决问题,所以上次升级后 flutter 文件夹本身出了问题? 无论如何,所有内容的全新安装都解决了问题。