Flutter - 在独立 class 中调用异步函数

Flutter - Calling an async function within an independent class

我在 main.dart 中声明了一个函数,它可以帮助我获得 deviceId。 我正在尝试将其设置为独立 class 的变量,其构造函数稍后在我的一个小部件中创建。

函数:

Future<String?> _getId() async {
  var deviceInfo = DeviceInfoPlugin();
  if (Platform.isIOS) { // import 'dart:io'
    var iosDeviceInfo = await deviceInfo.iosInfo;
    return iosDeviceInfo.identifierForVendor; // Unique ID on iOS
  } else {
    var androidDeviceInfo = await deviceInfo.androidInfo;
    return androidDeviceInfo.androidId; // Unique ID on Android
  }
}

在 class 中将其称为:

class _Data {
  String? fullname = '';
  String doctor = 's';
  String? deviceId = await _getId();
}

我遇到以下错误:

The await expression can only be used in an async function.


完整代码:

import 'dart:io';
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:device_info_plus/device_info_plus.dart';

Future<String?> _getId() async {
  var deviceInfo = DeviceInfoPlugin();
  if (Platform.isIOS) { // import 'dart:io'
    var iosDeviceInfo = await deviceInfo.iosInfo;
    return iosDeviceInfo.identifierForVendor; // Unique ID on iOS
  } else {
    var androidDeviceInfo = await deviceInfo.androidInfo;
    return androidDeviceInfo.androidId; // Unique ID on Android
  }
}

void main() => runApp(const MaterialApp(
  title: 'Manager',
  home: RegisterPage(),
));


class RegisterPage extends StatefulWidget {
  const RegisterPage ({Key? key}) : super(key: key);
  @override
  State<StatefulWidget> createState() => _RegisterPageState();
}

class _Data {
  String? fullname = '';
  String doctor = 's';
  String? deviceId = await _getId();
}

class _RegisterPageState extends State<RegisterPage> {
  final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
  _Data _data = _Data();

  void submit() {
      _formKey.currentState!.save();
      print('Printing the login data.');
      print('Fullname: ${_data.fullname}');
      print('Doctor: ${_data.doctor}');
      print('Device Id: ${_data.getDeviceId()}');
  }

  @override
  Widget build(BuildContext context) {
    final Size screenSize = MediaQuery.of(context).size;

    return Scaffold(
      appBar: AppBar(
        title: const Text('Manager'),
      ),
      body: Container(
          padding: const EdgeInsets.all(20.0),
          child: Form(
            key: _formKey,
            child: ListView(
              children: <Widget>[
                TextFormField(
                    keyboardType: TextInputType.text,
                    decoration: const InputDecoration(
                        hintText: 'John Doe',
                        labelText: 'Full name'
                    ),
                    onSaved: (String? value) {
                      _data.fullname = value;
                    }
                ),
                Container(
                  width: screenSize.width,
                  margin: const EdgeInsets.only(
                      top: 20.0
                  ),
                  child: ElevatedButton(
                    onPressed: submit,
                    child: const Text(
                      'Register',
                      style: TextStyle(
                          color: Colors.white
                      ),
                    ),
                  ),
                )
              ],
            ),
          )
      ),
    );
  }
}

点击提交时显示正确的全名值,但调用设备 ID 时出错

await 关键字只能与 async 函数一起使用。

仅使用函数,但在这里您在 class 中调用了 await _getId() 而不是在函数中。

试试这个。


  @override
  void initState() {
    // TODO: implement initState
    super.initState();

    _getId().then((value) {
      _data.deviceId = value;
    });
    //print(_data.deviceId);
  }

您想从异步操作的结果中初始化 deviceId。部分选项:

  • 声明Future<String?> deviceId = _getId();并要求所有调用者在访问它时await它。

  • 稍后初始化:

    class _Data {
      String? deviceId;
    
      _Data() {
        _getId().then((id) => deviceId = id);
      }
    }
    

    请注意,使用这种方法,调用者将不会在 deviceId 最终初始化时收到通知。

  • 让调用者异步初始化您的 class:

    class _Data {
      String? deviceId;
    
      _Data._(this.deviceId);
    
      static Future<_Data> newData() async {
        var id = await _getId();
        return _Data._(id);
      }
    }
    

有些相关:

您正在做的很多事情都会被认为是不好的做法。我将进行一些更改,最后回答您的问题。定义你的 _Data class 如下:

class _Data {
  String? fullname; 
  String doctor; 
  String? deviceId; 
  _Data(this.fullname, this.doctor, this.deviceId);
}

这样您的数据模型就不会被硬编码。您也可以考虑将这些字段设置为最终字段,除非您有充分的理由不这样做。

声明数据状态变量:

_Data? _data;

在您的状态中定义 initData 方法:

  Future<void> initData() async {
    var dat = _Data("fn", "doc", await _getId());
    setState(() {_data = dat; });
  }

最终覆盖 initState:

  @override
  void initState() {
    super.initState();
    initData();
  }

在您的构建方法中,您可以注意该字段是否为空(检查它是否已被初始化)。一旦你得到它,这里有很多改进的空间 运行。首先,您不应该将 getId 方法设为顶级,最好将其放在服务中,并且您应该考虑使用未来的构建器,而不是让 _data 状态属性可为空。