I have declared a function in my main.dart that would help me get the deviceId
.
I am trying to set this to a variable of an independent class, whose constructor is later created in one of my widget.
Function:
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
}
}
Calling it in a class as:
class _Data {
String? fullname = '';
String doctor = 's';
String? deviceId = await _getId();
}
I get below error:
The await expression can only be used in an async function.
Complete code:
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
),
),
),
)
],
),
)
),
);
}
}
It displays correct value for fullname on clicking submit but gives error for calling device id
CodePudding user response:
await keyword can only used with async function.
only with function, but here you called await _getId()
inside a class not inside a function.
try this.
@override
void initState() {
// TODO: implement initState
super.initState();
_getId().then((value) {
_data.deviceId = value;
});
//print(_data.deviceId);
}
CodePudding user response:
You want to initialize deviceId
from the result of an asynchronous operation. Some options:
Declare
Future<String?> deviceId = _getId();
and require all callers toawait
it when accessing it.Initialize it later:
class _Data { String? deviceId; _Data() { _getId().then((id) => deviceId = id); } }
Note that with this approach, callers will not be notified when
deviceId
is eventually initialized.Make callers initialize your class asynchronously:
class _Data { String? deviceId; _Data._(this.deviceId); static Future<_Data> newData() async { var id = await _getId(); return _Data._(id); } }
Somewhat related: How to await future in global main dart of flutter?
CodePudding user response:
Many of the things you are doing would be considered bad practice. I will lay out a few changes and finally answer your question. Define your _Data class as follows:
class _Data {
String? fullname;
String doctor;
String? deviceId;
_Data(this.fullname, this.doctor, this.deviceId);
}
This way your data model is not hardcoded. You may also consider making the fields final unless you have a good reason not to.
Declare the data state variable:
_Data? _data;
Define the initData method inside your state:
Future<void> initData() async {
var dat = _Data("fn", "doc", await _getId());
setState(() {_data = dat; });
}
Finally override initState:
@override
void initState() {
super.initState();
initData();
}
Inside your build method you can pay attention to whether or not the field is null (checking if it has been initialized). There's a bunch of room for improvement here once you get it running. First you should not make the getId method top level, it would be better to have it inside a service, and you should consider using a future builder instead of having the _data state attribute nullable.