Flutter get_it 和 FutureBuilder 无法使用热重载
Posted
技术标签:
【中文标题】Flutter get_it 和 FutureBuilder 无法使用热重载【英文标题】:Flutter get_it and FutureBuilder not working with hot reload 【发布时间】:2020-02-08 03:18:24 【问题描述】:下面的应用程序按预期工作,但不幸的是它不适用于热重载。我想知道如何使用它进行热重载。
代码所做的只是等待特定的Future<String>
可用,然后在屏幕上显示该字符串。在等待期间,会显示一个进度指示器。
正如我所说,这可以按预期工作,但问题是如果我更改任何内容(我的意思只是简单的装饰性内容)并且热重载启动,应用程序将永远坐在那里显示进度指示器,因为 @987654322 @ 停留在 ConnectionState.waiting
模式。
这是代码更详细的作用:
我在GetIt
中注册了一个String
对象作为单例。由于该字符串包含在 Future
中,因此代码必须等待它准备好才能注册。
(在实际代码中,我从资产加载 JSON 字符串。这就是为什么它在 Future
中。)
FutureBuilder
通过等待 GetIt
向名为 readyFuture
的属性发出信号,等待字符串单例可用。
当字符串可用时,FutureBuilder
会在屏幕上显示它。在此之前,将显示 CircularProgressIndicator
。
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;
),
);
我的 pubspec.yaml 中有这些依赖项:
get_it: ^3.0.1
provider: ^3.1.0
【问题讨论】:
在这种情况下,热重载到底会发生什么?我就是这么用的,还没出问题 【参考方案1】:问题在于 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,);
),
);
【讨论】:
您好,感谢您告诉我。我很快就会重温信号部分。 作为新的 API FutureFirebase.initializeApp()
时对我的 FutureBuilder
效果很好。以上是关于Flutter get_it 和 FutureBuilder 无法使用热重载的主要内容,如果未能解决你的问题,请参考以下文章
Flutter get_it 和 FutureBuilder 无法使用热重载
Flutter Bloc 状态更改未使用 get_it 更新 UI