【问题标题】:How to detect an asynchronous operation is over in streambuilder?如何在streambuilder中检测异步操作结束?
【发布时间】:2019-09-14 19:14:44
【问题描述】:

我正在像这样使用StreamBuilder -

StreamController streamController = StreamController.broadcast();

StreamBuilder(
    stream: streamController.stream,
    builder: (BuildContext context, AsyncSnapshot snapshot) {
      return (snapshot.hasData == true)  //THIS CONDITION!!!
          ? CircularProgressIndicator()
          : myWidget();
)

我正在像这样添加到我的信息流中 -

onPressed: () {
     streamController.add(null);
 },

我无法理解显示进度指示器或小部件应检查的条件。因为我没有传递任何数据,所以我不能使用hasData。我尝试传递虚拟数据,但hasData 永远不会变为假(即使在异步函数结束后)。 我尝试使用connectionState,但它始终处于活动状态。我不知道为什么它没有变为waiting 状态。当我使用FutureBuilder 时会这样。 (我以为我可以检查状态是否为waiting,显示进度指示器,但这不起作用。为什么??)

请帮忙。

【问题讨论】:

  • 你想用streamController.add() 方法实现什么?调用onPressed 时会发生什么?
  • 我调用一个 API 并等待它完成。由于它有点慢,我想在完成之前显示进度指示器。
  • 所以你需要FutureBuilder,而不是StreamBuilder
  • 当按下按钮时调用此 API,所以最初当屏幕打开时,我只希望 myWidget 出现。当我们必须在打开屏幕时调用 API 时,我们不使用FutureBuilder 吗?

标签: asynchronous dart flutter stream


【解决方案1】:

总是当我有一个返回我未来数据的异步调用并且我需要这个响应来使用我认为在 BLoC 模式中的流来更新我的 UI 层时。需要更多代码,但会简化您的问题,使您的代码更具可读性、可扩展性,并将流和异步调用与 UI 代码保持一致。

你的情况很简单:

enum DownloadState { NO_DOWNLOAD,  DOWNLOADING, SUCCESS }

一个枚举来跟踪async调用网络API调用的状态。

class Bloc {

  final ApiClass api = new ApiClass();   // simulating your downloader object
  final StreamController controller = StreamController<DownloadState>.broadcast(); 
  Stream get dataState => controller.stream; // exposing your stream output

 void _changeState( final DownloadState state ) => controller.sink.add( state );

  void downloadData(){
      _changeState( DowloadState.DOWNLOADING );     
      // assuming that this call returns a Future object.
      api.downloadData().then(  (yourNetworkData) {
         // handle your downloaded data 
        _changeState( DownloadState.SUCCESS );
       }  ).catchError( (apiError) =>  controller.sink.addError( apiError ); ); 
 }
}

一个公开流的 BLoC 类,在该类中,我们创建通过示例调用网络 API 的方法,当获取结果时,我们可以保存值、转换这些值、使用流和其他东西发送到 UI。在 downloadData 中,在 Future 对象完成后,我们只需将 DownloadState 值放入流中,这将强制在 UI 层中使用 StreamBuilder 帮助重建正在侦听 controller.stream 的小部件。如果我们从网络调用中得到一些错误,我们将它放在流错误输出controller.sink.addError 中,并且在 UI 层我们可以使用 snapshot.hasError 属性来检查它。

在您的 UI 层中...

Bloc bloc = Bloc(); // you can create a instance of BLoC in initState or in widget contructor...
StreamBuilder<DownloadState>(
    stream: bloc.dataState, // bloc get method that returns stream output.
    initialData: DownloadState.NO_DOWNLOAD. // this will be the inital value. It's optional
    builder: (BuildContext context, AsyncSnapshot snapshot) {
      if (snapshot.hasData){
          switch(snapshot.data){
               case  DownloadState.NO_DOWNLOAD:
                  return NoDownloadWidget();
               case  DownloadState.DOWNLOADING:
                  return CircularProgressIndicator();
                case  DownloadState.SUCCESS:
                   return myWidget();
          }
      }
       return ErrorWidget( snapshot.error );
)

在 onPress 事件中

onPressed: () => bloc.downloadData();

使用这种方法,您可以删除 UI 层流对象和控制器,不需要 setState 调用,您将拥有一个包含业务逻辑和外部 api 调用的特定文件,这可以使我们拥有的此类工作变得更加容易Futures 和 Streams 一起工作。

希望对你有帮助。

【讨论】:

    猜你喜欢
    • 2023-03-06
    • 2014-08-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-16
    • 1970-01-01
    • 1970-01-01
    • 2012-01-18
    相关资源
    最近更新 更多