颤振/飞镖异步不等待

Posted

技术标签:

【中文标题】颤振/飞镖异步不等待【英文标题】:Flutter/Dart Async Not Waiting 【发布时间】:2019-05-07 00:18:27 【问题描述】:

我正在构建我的第一个 Flutter 应用程序,但遇到了一些异步问题。

当我的应用程序执行时,我希望它请求权限并等待它们被授予。我的 main() 函数如下所示:

import 'permission_manager.dart' as Perm_Manager;

void main() async

  //Ensure valid permissions
  Perm_Manager.Permission_Manager pm = Perm_Manager.Permission_Manager();
  var res = await pm.get_permissions();
  print(res);

  return runApp(MyApp());
 

Permission Manager 类的 get_permissions() 函数使用 Flutter Simple Permissions 包来检查和请求权限。

import 'package:simple_permissions/simple_permissions.dart';
import 'dart:io' as IO;
import 'dart:async';

class Permission_Manager 
  /* Get user permissions */

  Future<bool> get_permissions() async
  
    //android handler
    if (IO.Platform.isAndroid)
    
        //Check for read permissions
        SimplePermissions.checkPermission(Permission.ReadExternalStorage).then((result)
        
          //If granted
          if (result)
            return true;

          //Otherwise request them
          else
          
            SimplePermissions.requestPermission(Permission.ReadExternalStorage)
            .then((result)
            
              // Determine if they were granted
              if (result == PermissionStatus.authorized)
                return true;
              else
                IO.exit(0); //TODO - display a message
            );
          
        );
    

    else
      return true;
  

当我运行应用程序时,它不会等待函数按预期完成,而是在 Future 更新之前打印“res”的值。

Launching lib\main.dart on Android SDK built for x86 in debug mode...
Built build\app\outputs\apk\debug\app-debug.apk.
I/SimplePermission(15066): Checking permission : android.permission.READ_EXTERNAL_STORAGE
I/flutter (15066): null
I/SimplePermission(15066): Requesting permission : android.permission.READ_EXTERNAL_STORAGE

Future 在函数中途返回一个值!有谁知道我做错了什么?

【问题讨论】:

【参考方案1】:

要等待某事,您必须在未来调用 await 关键字而不是 .then

final result = await future;
// do something

而不是

future.then((result) 
  // do something
);

如果你真的想使用.then,那么你可以等待生成的未来:

await future.then((result) 
  // do something
);

只需确保在使用嵌套异步调用时,每个调用都使用 async 关键字:

await future.then((result) async
    // do something
    await future.then((result_2) 
       // do something else
    );
);

【讨论】:

"await" 用于调用异步函数的 main() 函数。尽管我的印象是“then”和“await”虽然语法不同(“then”在完成后运行一个函数)但它们的操作方式相同。 不,他们没有。你真的必须使用await 来自 Dart 文档 (dartlang.org/tutorials/language/futures):“要暂停执行直到未来完成,请在异步函数中使用 await(或使用 then())。”但尽管如此,我确实在 main() 函数中使用了 await 无济于事。 一次是不够的。在您的示例中,您需要的不仅仅是一个 await 我认为你不能等待生成的未来。生成的未来对于 then() 运行的回调函数是本地的,并且执行诸如“await SimplePermissions.checkPermission(Permission.ReadExternalStorage).then((result) ...”之类的操作会产生错误。确实可以返回从回调生成未来,但由于插件不返回布尔值,您需要重写 main() 中的大部分函数【参考方案2】:

搞定了。该问题似乎已使用 Completer 解决:

import 'package:simple_permissions/simple_permissions.dart';
import 'dart:io' as IO;
import 'dart:async';

class Permission_Manager 
  /* Get user permissions */

  final Completer c = new Completer();

  Future get_permissions() async
  

    //Android handler
    if (IO.Platform.isAndroid)
    
        //Check for read permissions
        SimplePermissions.checkPermission(Permission.ReadExternalStorage).then((result)
        
          //If granted
          if (result)
          
            c.complete(true);
          
          //Otherwise request them
          else
          
            SimplePermissions.requestPermission(Permission.ReadExternalStorage).then((result)
            
              // Determine if they were granted
              if (result == PermissionStatus.authorized)
              
                c.complete(true);
              
              else
              
                IO.exit(0); //TODO - display a message
              
            );
          
        );
    

    else
    
      c.complete(true);
    

    return c.future;
  


【讨论】:

这会使get_permissions 上的async 标志无用。 应用程序需要任何功能的读取权限,但简单权限插件异步操作。具体来说,打开应用程序时会读取下载目录中的所有文件。此解决方案会阻止应用程序读取目录,直到授予权限。如果有一种方法可以同步使用插件,那将是理想的,但我认为这是不可能的。 我不是说代码不行,而是语法不对。 参考文档 (pub.dartlang.org/packages/simple_permissions#-readme-tab-)。在没有 async 标志的情况下运行代码并返回非未来 bool 会产生与初始问题中看到的相同的结果(由于插件代码异步运行)。还有其他方法吗?

以上是关于颤振/飞镖异步不等待的主要内容,如果未能解决你的问题,请参考以下文章

颤振异步等待未按预期工作

如何取消颤振/飞镖集团中的“等待”

等待异步函数在 dart 中无法正确执行

颤振异步调用不会在 initState() 中异步运行

如何在飞镖中控制异步执行流程[重复]

异步/等待/然后在 Dart/Flutter 中