Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/flutter/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Flutter Flatter get_it和FutureBuilder不使用热重新加载_Flutter_Hot Reload_Flutter Provider - Fatal编程技术网

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
非常有效。在这种情况下,热重新加载会发生什么?我就是这么用的,还没有问题