下面的应用程序可以正常运行,但不幸的是,它无法与热重装一起使用。我想知道如何使用它进行热重装。
所有代码所做的只是简单地等待特定的Future<String>
可用,然后在屏幕上显示该字符串。等待期间,将显示进度指示器。
正如我说的那样,它可以按预期工作,但是问题是,如果我进行了任何更改(我的意思是简单的化妆品),并且热加载开始,应用程序将永远坐在那里显示进度指示器,因为{{ 1}}处于connectionState
模式。
这是代码更详细的作用:
我在ConnectionState.waiting
中将String
对象注册为单例。由于该字符串包装在GetIt
中,因此代码必须等待其准备好后才能注册。
(在真实代码中,我正在从资产中加载JSON字符串。这就是为什么它位于Future
中。)
Future
通过等待FutureBuilder
发信号通知名为GetIt
的属性来等待字符串单例可用。
当字符串可用时,readyFuture
将其显示在屏幕上。在此之前,将显示FutureBuilder
。
CircularProgressIndicator
我的pubspec.yaml中具有以下依赖项:
import 'package:flutter/material.dart';
import 'package:get_it/get_it.dart';
GetIt locator = GetIt.instance;
void setupLocator() async {
final str = await Future<String>.delayed(Duration(seconds: 3), () => "hello");
locator.registerSingleton(str, signalsReady: true);
locator.signalReady(str);
}
void main() {
setupLocator();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: FutureBuilder<void>(
future: locator.readyFuture,
builder: (BuildContext context, AsyncSnapshot<void> snapshot) {
Widget result;
switch (snapshot.connectionState) {
case ConnectionState.none:
case ConnectionState.active:
case ConnectionState.waiting:
result = Center(child: CircularProgressIndicator());
break;
case ConnectionState.done:
if (snapshot.hasError)
result = Center(child: Text('Error: ${snapshot.error}'));
else
result = Center(child: Text('${locator.get<String>()}'));
break;
}
return result;
}
),
);
}
}
答案 0 :(得分:0)
问题在于GetIt使用广播流GetIt.ready
来表示已准备就绪。广播流的问题是信号在热重载时丢失。
另一个独立的问题是,如果GetIt.ready
广播流没有侦听器,则就绪信号将丢失。因此,这里存在一个竞争条件:您必须确保FutureBuilder在发送就绪信号之前正在监听GetIt.ready
,通常这是不可能的。
我想出的解决方法是使用Completer
对象作为就绪信号。 (请参见下面的代码中的locatorReady
。)我向GetIt.ready
添加了一个侦听器,并向Completer
对象发出信号。
FutureBuilder
等待Completer.future
属性。
(我是Flutter的新手,但在我看来,在GetIt中使用广播流不是一个好选择。我认为最好使用Completer
。)
这是更新的代码:
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:get_it/get_it.dart';
GetIt locator = GetIt.instance;
Completer<void> locatorReady = Completer<void>();
void setupLocator() async {
final str = await Future<String>.delayed(Duration(seconds: 8), () => "hello");
locator.registerSingleton(str, signalsReady: true);
locator.ready.listen((_){locatorReady.complete();});
locator.signalReady(str);
}
void main() {
setupLocator();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: FutureBuilder<void>(
future: locatorReady.future,
builder: (BuildContext context, AsyncSnapshot<void> snapshot) {
Widget result;
switch (snapshot.connectionState) {
case ConnectionState.none:
case ConnectionState.active:
case ConnectionState.waiting:
result = Text('Awaiting result ...');
break;
case ConnectionState.done:
if (snapshot.hasError)
result = Text('Error: ${snapshot.error}');
else
result = Text('Result: ${locator.get<String>()}');
break;
}
return Center(child: result,);
}
),
);
}
}