使用 Provider (Flutter) 包进行异步异常处理 (Firebase)

Posted

技术标签:

【中文标题】使用 Provider (Flutter) 包进行异步异常处理 (Firebase)【英文标题】:Async Exception-Handling (Firebase) with the Provider (Flutter) Package 【发布时间】:2020-07-01 00:05:20 【问题描述】:

1。问题

我正在使用 try-catch-finally1 动态来处理我的应用程序的简单身份验证包中的 Firebase 异常处理。在其中,当我收到来自 Firebase 身份验证服务的错误时,我会更新(自定义)TextFormField 上的 labelText,以向用户显示发生了错误。

但是,notifyListeners() 显然是与 catch 子句同时运行的,导致重建不会与异常处理同步发生。

目前,我基本上都在使用ChangeNotifierProvider,但我应该更改为FutureProvider 动态。如果是这样,最好的方法是什么?


1 我也尝试过使用then-catchError-whenComplete

2。守则

2.1 完整代码(可选)

目前项目中的完整代码有点长,但我认为下面显示的内容就足够了。

无论如何,如果您想检查所有内容,可以使用整个项目:flutter_firebase_auth_benchmark。

相关文件有:

firebase_auth.dart:带有相关数据的provider 类。 login_screen.dartemail_field 通过 Consumer 小部件提供 provider 数据。 password_reset_workflow.dart:调用相关方法的按钮通过AnimatedSwitcher放入LoginScreen

2.2 提供者类

我不得不使用Future.delayed 来手动同步notifyListeners()build() 方法——我知道,我知道,这很糟糕......

class Auth extends ChangeNotifier 
  String _errorMsg;

  String get errorMsg => _errorMsg;

  ...

  Future<void> sendPasswordResetWithEmail(@required String email) async 
    try 
      await FirebaseAuth.instance.sendPasswordResetEmail(email: email);
     catch(e) 
      switch (e.code) 
        case 'ERROR_USER_NOT_FOUND':
          _errorMsg = 'user not found';
          break;
        default:
          throw UnknownPasswordResetError(
              'Unknown error for password reset with Firebase.');
      
     finally 
      notifyListeners();
      await Future.delayed(Duration(milliseconds: 10));
    
  

2.3 我的自定义TextFormField 小部件

应用中有这样的东西:

return Consumer<Auth>(
  builder: (context, auth, _) 
    return AuthTextFormField(
      ...,
      errorMsgFromServer: auth.errorMsg,
    );
  
);

最后,验证按钮在if 子句中使用formKey.currentState.validate() 异步触发await auth.sendPasswordResetWithEmail

【问题讨论】:

到目前为止,我最接近回答这个问题的是this SO answer。 【参考方案1】:

notifyListeners() 显然与 catch 子句同时运行

notifyListeners()finally 块内,finally 将始终被执行,无论是否有错误,这就是为什么总是调用 notifyListeners()

另外,使用Future.delayed 来同步事件是很糟糕的,你应该为它做另一个架构。

【讨论】:

我知道notifyListeners() 将始终被执行,但我希望它在错误处理之后执行,而不是在完成try 子句之后执行。而且我也知道使用Future.delayed 来同步事件非常糟糕,这可能是发布问题的全部原因。 “在错误处理之后而不是在try之后”是什么意思?很抱歉,我无法理解您的英语 Fala em português que depois eu edito a resposta em inglês pra todo mundo entender。 从众多变体来看,代码执行的顺序似乎是:trycatchfinally 并行。所以notifyListeners() 会在errorMsg 被更新时被调用。 Future.delayed 调用将使事情手动同步。但我不确定所有的顺序,这只是我在调试时能够猜到的。 Eu acho que você ta abusando um pouco dessa arquitetura... Você pode simplificar as coisas com FutureBuilder, StreamBuilder 等 e nem precisar de um ChangeNotifier

以上是关于使用 Provider (Flutter) 包进行异步异常处理 (Firebase)的主要内容,如果未能解决你的问题,请参考以下文章

使用 geolocator 和 provider 以及 flutter_maps 获取位置

使用 Flutter Provider 管理嵌套类的状态

flutter_bloc/provider RepositoryProvider vs Provider

如何使用 Provider 实现 Flutter 本地化?

将提供程序包添加到 Flutter Web 项目时出错

Flutter Provider:提供 2 个流,一个依赖另一个