Flutter Flatter get_it和FutureBuilder不使用热重新加载
下面的应用程序按预期工作,但不幸的是,它无法与热重新加载一起工作。我想知道如何使用它进行热重新加载 代码只需等待特定的Flutter Flatter get_it和FutureBuilder不使用热重新加载,flutter,hot-reload,flutter-provider,Flutter,Hot Reload,Flutter Provider,下面的应用程序按预期工作,但不幸的是,它无法与热重新加载一起工作。我想知道如何使用它进行热重新加载 代码只需等待特定的未来可用,然后在屏幕上显示该字符串。当它等待时,将显示一个进度指示器 import 'package:flutter/material.dart'; import 'package:get_it/get_it.dart'; GetIt locator = GetIt.instance; void setupLocator() async { final str = awa
未来可用,然后在屏幕上显示该字符串。当它等待时,将显示一个进度指示器
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;
}
),
);
}
}
正如我所说的,这是可以预期的,但问题是如果我改变了任何东西(我指的只是简单的装饰性的东西)并开始热加载,应用程序将永远坐在那里显示进度指示器,因为connectionState
处于connectionState.waiting
模式
这是代码更详细的功能:
我在GetIt
中将String
对象注册为单例。由于该字符串被包装在Future
中,因此代码必须等待它准备就绪后才能注册
(在真正的代码中,我正在从一个资产加载一个JSON字符串。这就是为什么它在未来的)
FutureBuilder
等待字符串singleton可用,方法是等待GetIt
向名为readyFuture
的属性发送信号
当字符串可用时,FutureBuilder
将其显示在屏幕上。在此之前,将显示一个循环压缩机指示器
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;
}
),
);
}
}
问题是GetIt使用一个广播流,GetIt.ready
,来表示它已经准备好了。广播流的问题是信号在热重新加载时丢失
另一个独立的问题是,如果没有GetIt.ready
广播流的侦听器,那么ready信号将丢失。因此这里有一个竞争条件:在发送就绪信号之前,您必须确保FutureBuilder正在收听GetIt.ready
,这通常是不可能的
我想到的解决方法是使用一个补码器
对象作为就绪信号。(请参见下面代码中的locatorReady
)我在GetIt.ready
中添加了一个侦听器,它向完成器发出信号
FutureBuilder
等待Completer.future
属性
(我是一个新手,但在我看来,在GetIt中使用广播流不是一个好选择。我认为一个完成器会更好。)
这是更新的代码:
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,);
}
),
);
}
}
导入'dart:async';
进口“包装:颤振/材料.省道”;
导入“package:get_it/get_it.dart”;
GetIt locator=GetIt.instance;
完成器定位器就绪=完成器();
void setupLocator()异步{
final str=等待未来。延迟(持续时间(秒:8),()=>“你好”);
locator.registerSingleton(str,signalsrady:true);
locator.ready.listen(({locatorReady.complete();});
信号准备定位器(str);
}
void main(){
setupLocator();
runApp(MyApp());
}
类MyApp扩展了无状态小部件{
@凌驾
小部件构建(构建上下文){
返回材料PP(
主页:MyHomePage(),
);
}
}
类MyHomePage扩展了无状态小部件{
@凌驾
小部件构建(构建上下文){
返回脚手架(
正文:未来建设者(
未来,未来,
生成器:(BuildContext上下文,异步快照){
小部件结果;
交换机(快照.连接状态){
案例连接状态。无:
案例连接状态.active:
案例连接状态。正在等待:
结果=文本('等待结果…');
打破
案例连接状态。完成:
if(snapshot.hasError)
结果=文本('Error:${snapshot.Error}');
其他的
结果=文本('result:${locator.get()}');
打破
}
返回中心(子项:结果,);
}
),
);
}
}
嗨,谢谢你让我知道。我将很快重新讨论信号部分。作为新的API Future allReady(),您认为这是什么;未来的isReady({Object instance,String instanceName});而不是直接暴露未来或流?通过这种方式,我们可以获得更多的控制,我可以轻松地纠正上述问题。这是一个很好的答案,在使用Firebase.initializeApp()
时,它对我的FutureBuilder
非常有效。在这种情况下,热重新加载会发生什么?我就是这么用的,还没有问题