Асинхронный режим Flutter / Dart не ожидает

Я создаю свое первое приложение 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());
} 

Функция get_permissions () класса Permission Manager использует пакет 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;
  }
}

Когда я запускаю приложение, оно не дожидается завершения функции, как предполагалось, и выводит значение «res» перед обновлением Future.

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 возвращает значение в середине функции! Кто-нибудь знает, что я делаю не так?

10
0
14 359
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Чтобы чего-то ждать, вам нужно вызвать ключевое слово 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», выполняющим функцию после завершения), они работали одинаково.

Topazoo 05.12.2018 13:56

Нет, они этого не делают. Вам действительно нужно использовать await

Rémi Rousselet 05.12.2018 13:58

Из документации Dart (dartlang.org/tutorials/language/futures): «Чтобы приостановить выполнение до тех пор, пока не завершится будущее, используйте await в асинхронной функции (или используйте then ())». Но, несмотря на это, я безрезультатно использовал await в своей функции main ().

Topazoo 05.12.2018 14:00

Один раз недостаточно. вам нужно больше, чем один await в вашем примере

Rémi Rousselet 05.12.2018 14:12

Не думаю, что можно ждать сгенерированного будущего. Сгенерированное будущее является локальным для функции обратного вызова, запущенной с помощью then () и выполняющей что-то вроде "await SimplePermissions.checkPermission (Permission.ReadExternalSto‌ rage) .then ((result) {..." генерирует ошибку. Это правда, что вы могли бы вернуть сгенерированное будущее из обратного вызова, но поскольку плагин не возвращает логические значения, вам нужно будет переписать большую часть функции в main ()

Topazoo 05.12.2018 14:34

Ах ты прав! Мои извинения. Вы действительно можете дождаться результата. К сожалению, в этом случае я возвращаю значения, а он по-прежнему не работает :(. I/SimplePermission(18817): Checking permission : android.permission.READ_EXTERNAL_STORAGE I/flutter (18817): Instance of 'Future<bool>' I/SimplePermission(18817): Requesting permission : android.permission.READ_EXTERNAL_STORAGE

Topazoo 05.12.2018 14:48

НЕВАЖНО!! Объявление первой функции then () как асинхронной (поскольку вторая является вложенной) выполнило свою работу. Спасибо за вашу помощь, Реми.

Topazoo 05.12.2018 15:01

Идеально. Я все же рекомендую нет использовать then. Читать сложнее и ничего не приносит по сравнению со сплющенным async / await

Rémi Rousselet 05.12.2018 15:11

@ RémiRousselet, вы можете мне помочь с этим вопросом. Я тоже столкнулся с аналогичной проблемой. stackoverflow.com/questions/62502334/…

Roxx 21.06.2020 20:40

Все заработало. Проблема, похоже, решена с помощью 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;
  }

}

что делает ваш флаг async на get_permissions бесполезным.

Rémi Rousselet 05.12.2018 14:07

Приложению требуются разрешения на чтение для любых функций, но плагин Simple Permissions работает асинхронно. В частности, при открытии приложение читает все файлы в каталоге Downloads. Это решение не позволяет приложению читать каталог до тех пор, пока не будут предоставлены разрешения. Если есть способ использовать плагин синхронно, это было бы идеально, но я не думаю, что это возможно.

Topazoo 05.12.2018 14:14

Я не говорю, что код не работает, но синтаксис неправильный.

Rémi Rousselet 05.12.2018 14:15

Документы для справки (pub.dartlang.org/packages/simple_permissions#-readme-tab-). Выполнение кода без флага async и возврат логического значения, отличного от Future, дает те же результаты, что и в исходном вопросе (из-за асинхронного выполнения кода плагина). Есть другой способ сделать это?

Topazoo 05.12.2018 14:17

Другие вопросы по теме