如果网络请求失败,如何在流的基础上显示警报对话框

Posted

技术标签:

【中文标题】如果网络请求失败,如何在流的基础上显示警报对话框【英文标题】:How can I show alert dialog on base of a stream in case network request fails 【发布时间】:2021-03-08 07:49:05 【问题描述】:

这是我到目前为止的代码。 _mBlock.mSpotStream 是一个网络请求。 我很感兴趣如何在_mBlock.getSpots() 因网络错误而失败的情况下显示警报对话框,同时将列表保留在屏幕上。我尝试将警报对话框作为小部件返回,但在这种情况下我无法关闭它。

 @override
  Widget build(BuildContext context) 
    return Scaffold(
      appBar: AppBar(title: Text(Strings.of(context).spot_list_title), centerTitle: true),
      body: Container(
          child: Column(
        children: [
          Expanded(
              child: Stack(
            children: [
              StreamBuilder<List<SpotDto>>(
                stream: _mBlock.mSpotStream,
                builder: (context, snapshot) 
                  return RefreshIndicator(
                    onRefresh: () 
                      return _mBlock.getSpots();
                    ,
                    child: ListView.builder(
                      itemCount: snapshot.data?.length ?? 0,
                      itemBuilder: (context, position) 
                        return SpotListItem(snapshot.data[position], () 
                          ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(position.toString())));
                        );
                      ,
                    ),
                  );
                ,
              ),
              Column(
                children: [
                  Expanded(
                    child: StreamBuilder<Progress<bool>>(
                      stream: _mBlock.mStateStream,
                      builder: (context, snapshot) 
                        return Visibility(
                          visible: snapshot.data?.mIsLoading ?? false,
                          child: SizedBox.expand(
                            child: Container(
                              color: Colors.blue.withOpacity(Dimens.overlayOpacity),
                              child: Center(
                                child: CircularProgressIndicator(),
                              ),
                            ),
                          ),
                        );
                      ,
                    ),
                  )
                ],
              )
            ],
          ))
        ],
      )),
    );
  


showAlertDialog(BuildContext context, SpotListBlock block) 
  StreamBuilder<Error<String>>(
    stream: block.mErrorStream,
    builder: (context, snapshot) 
      if (snapshot.hasData) 
        return AlertDialog(
          title: Text(Strings.of(context).error),
          content: Text(snapshot.data.mErrorMessage),
          actions: [
            FlatButton(
              child: Text("Cancel"),
              onPressed: () 
                Navigator.pop(context, true);
              ,
            )
          ],
        );
       else 
        return Row();
      
    ,
  );

【问题讨论】:

【参考方案1】:

最后,我已经这样修复了它,这是我能够修复它的唯一方法,感谢任何评论: 我的修复是基于这个要点https://gist.github.com/felangel/75f1ca6fc954f3672daf7962577d56f5

class SpotListScreen extends StatelessWidget 
  final SpotListBlock _mBlock = SpotListBlock();

  @override
  Widget build(BuildContext context) 
    return Scaffold(
      appBar: AppBar(title: Text(Strings.of(context).spot_list_title), centerTitle: true),
      body: Container(
          child: Column(
        children: [
          Expanded(
              child: Stack(
            children: [
              StreamBuilder<List<SpotDto>>(
                stream: _mBlock.mSpotStream,
                builder: (context, snapshot) 
                  return RefreshIndicator(
                    onRefresh: () 
                      return _mBlock.getSpots();
                    ,
                    child: ListView.builder(
                      itemCount: snapshot.data?.length ?? 0,
                      itemBuilder: (context, position) 
                        return SpotListItem(snapshot.data[position], () 
                          ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(position.toString())));
                        );
                      ,
                    ),
                  );
                ,
              ),
              StreamBuilder<Error<String>>(
                stream: _mBlock.mErrorStream,
                builder: (context, snapshot) 
                  if (snapshot.hasData) 
                    SchedulerBinding.instance.addPostFrameCallback((_) 
                      showDialog(
                        context: context,
                        barrierDismissible: false,
                        builder: (_) 
                          return Scaffold(
                            body: Center(
                              child: RaisedButton(
                                child: Text('dismiss'),
                                onPressed: () 
                                  Navigator.pop(context);
                                ,
                              ),
                            ),
                          );
                        ,
                      );
                    );
                    return Container(
                      width: 0.0,
                      height: 0.0,
                    );
                   else 
                    return Container(
                      width: 0.0,
                      height: 0.0,
                    );
                  
                ,
              ),
              Column(
                children: [
                  Expanded(
                    child: StreamBuilder<Progress<bool>>(
                      stream: _mBlock.mStateStream,
                      builder: (context, snapshot) 
                        return Visibility(
                          visible: snapshot.data?.mIsLoading ?? false,
                          child: SizedBox.expand(
                            child: Container(
                              color: Colors.blue.withOpacity(Dimens.overlayOpacity),
                              child: Center(
                                child: CircularProgressIndicator(),
                              ),
                            ),
                          ),
                        );
                      ,
                    ),
                  )
                ],
              )
            ],
          ))
        ],
      )),
    );
  

块代码

Future<List<SpotDto>> getSpots() 
    var completer = new Completer<List<SpotDto>>();
    _reportsRepositoryImpl.getSpots().single.then((spotList) 
      addNewSpotsToList(spotList);
      completer.complete(spotList);
    ).catchError((Object obj) 
      switch (obj.runtimeType) 
        case DioError:
          _mErrorSink.add(Error((obj as DioError).message));
          completer.complete();
          break;
        default:
          completer.complete();
      
      _mSpotSink.add(_mSpotList);
    );

    return completer.future;
  

【讨论】:

【参考方案2】:

显示警报对话框只是一个简单的调用,例如:

await showDialog<bool>(
    context: context,
    builder: (BuildContext context) 
      return AlertDialog(
        title: 'alert!!!',
        content: 'hello world',
        actions: [
            FlatButton(child: Text('cancel'), onPressed: () => Navigator.pop(context, false)),
            FlatButton(child: Text('ok'), onPressed: () => Navigator.pop(context, true)),
        ],
      );
    ,
  )

当您拨打showDialog 时,屏幕上会显示一个对话框。

【讨论】:

但它会以这种方式将列表保留在屏幕上吗?此外,当我添加这样的对话框时,我无法使用 Navigator.pop(context, true) 丢失它 @Void 当然原始内容会出现在屏幕上。为什么 Navigator.pop 不能工作?能否请您提供更多详细信息? 或者,有两件事我还是不明白。 1)我的对话框根据错误显示不同的内容(添加到问题中)2)不知道,为什么弹出不起作用,触发了onTap,但对话框留在屏幕上 @Void 请提供更多详细信息...例如你的完整代码 谢谢,在您的帮助下,我终于能够描述这个问题,如果我在 StreamBuilder 中调用 showDialog,它会说它不是一个小部件,并且 streem 构建器应该返回一个小部件。所以我不能使用它,或者我应该以某种方式改变它。

以上是关于如果网络请求失败,如何在流的基础上显示警报对话框的主要内容,如果未能解决你的问题,请参考以下文章

在 App Delegate 中显示警报的方法失败,因为它的 rootViewController 不在 View Hierarcy 中

如何根据 Firebase Auth 错误消息在 Flutter 中显示自定义警报对话框?

如何在颤动中使用 bloc 模式进行错误处理?

在颤动中自动在应用程序主屏幕加载上显示警报对话框

如何在swift 5中的完成块内向用户显示警报

如何在 SwiftUI 中一个接一个地显示多个警报对话框?