Sockets and Future Functions in Dart - flutter

Summarize the Problem.
I am trying to write an async function that returns data when a receive is completed from a socket. I am having trouble returning the correct data from my async function. The error I am receiving is that the rtn variable is not set and can be null.
Describe what you've tried.
I've tried writing the async function but haven't been getting the desired result. I tried using the late keyword for the variable rtn but that resulted in a runtime exception that the variable was null.
Show some code.
Below, is the function giving me problems. Any advice or resources would be welcomed. I tried going over the Flutter documentation for async but it wasn't too helpful for me.
What I want is that the network data is returned from this async function.
Future<int> fetchNumVideos() async {
int rtn;
Socket.connect(baseStationAddresses[0],
baseStationPort, timeout: const Duration(seconds: 5)).then((socket) =>
{
socket.listen((data) {
String socketData = String.fromCharCodes(data);
print("socketData: $socketData");
rtn = int.parse(socketData);
},
onDone: ((){
socket.destroy();
})
),
}).catchError((onError) {
rtn = 0;
});
return rtn;
}
Thank you!

This issue has been solved by pskink's comment.
The solution was to use the Completer class.
Future<int> fetchNumVideos() async {
final completer = Completer<int>();
Socket.connect(baseStationAddresses[0],
baseStationPort, timeout: const Duration(seconds: 5)).then((socket) =>
{
socket.listen((data) {
String socketData = String.fromCharCodes(data);
print("socketData: $socketData");
completer.complete(int.parse(socketData));
},
onDone: ((){
socket.destroy();
})
),
}).catchError((onError) {
completer.complete(0);
});
return completer.future;
}

Related

ReadToken() is returning "Instance of 'Future<Object>'"

ReadToken() is returning "Instance of 'Future'"
I was following this tutorial on the Flutter Docs: https://docs.flutter.dev/cookbook/persistence/reading-writing-files.
So, my problem is that, if I just run ReadToken() without running the create function then the ReadToken() function always returns "Instance of 'Future'". Note: I made some changes to the ReadToken() function, like the name. The function is below.
Future<Object> readToken() async {
try {
final file = await _localFile;
// Read the file
final contents = await file.readAsString();
return contents;
} catch (e) {
// If encountering an error, return 0
return 0;
}
}
}
Is there anything that I'm doing wrong or anything that I should change?
You have to await readToken(). If you continue reading the documentation by the complete example section, it shows this example:
#override
void initState() {
super.initState();
widget.storage.readCounter().then((value) {
setState(() {
_counter = value;
});
});
}
It's using .then() instead of await, which await is a syntactic sugar for .then()
So, In your case it would be:
readToken().then((value) {
// Do something with the `value`
});

why my circularProgressIndicator having strange behavior when async function called?

Im calling a function to get data from Excel file and upload it to my Firestore as following
floatingActionButton: FloatingActionButton(onPressed: () async {
Utils.showLoading(context);
await FireStoreServices.bulkUploadFromExcelToFireStore(
collectionName: 'test',
fileName: 'test',
sheetName: 'test');
Navigator.pop(context);
}),
the problem is my Progress loading indicator not working as expected in this case (not spinning only shows and freeze until the function complete after that its popped)
i tried to replace the awaited function 'bulkUploadFromExcelToFireStore' with Future.delayed and it worked as expected
await Future.delayed(const Duration(seconds: 3), () {});
what might be the problem ?
here is the code of bulkUploadFromExcelToFireStore function
static Future bulkUploadFromExcelToFireStore(
{required String fileName,
required String sheetName,
required String collectionName}) async {
try {
final rowsData = await Utils.readExcelFileData(
excelFilePath: fileName, sheetName: sheetName);
rowsData.removeAt(0);
for (var row in rowsData) {
firebaseFirestore.collection(collectionName).doc(row[0]).set(data, SetOptions(merge: true));
}
} catch (e) {
print('Cached ERROR MESSAGE = = = = ${e.toString()}');
}
I added some validations inside your function to check for possible failures.
It would also be interesting to validate a failure warning and terminate the Progression Indication initialization.
static Future<String> bulkUploadFromExcelToFireStore({required String fileName, required String sheetName,required String collectionName}) async {
try {
final rowsData = await Utils.readExcelFileData(excelFilePath: fileName, sheetName: sheetName);
rowsData.removeAt(0);
if(rowsData.length == 0) {
return "No Items!";
} else {
for (var row in rowsData) {
firebaseFirestore?.collection(collectionName)?.doc(row[0])?.set(data, SetOptions(merge: true));
}
return "Item allocated!";
}
} catch (e) {
return e.toString();
}
}

Asynchronous method not running in proper order

I have these methods, for some reason fetchItems is being called first before initPosition, how come dart wont wait for it to finish and proceeds to the second method? I've added async/await but it still doesn't work. I've also checked my backend logs to confirm this. Am I doing something wrong?
Future<void> initPosition() async {
if (_latitude != null && _longitude != null) {
await Socket.updatePosition(
lat: 51,
lon: 17,);
}
}
Future<void> initMarkers() async {
await initPosition();
await Provider.of<Items>(context, listen: false)
.fetchItems();
}
void initMapState() async {
await getCurrentLocation().then((_) async {
await initMarkers();
setState(() {
_loaded = true;
});
});
}
#override
void initState() {
super.initState();
_location.enableBackgroundMode(enable: false);
WidgetsBinding.instance?.addPostFrameCallback((_) {
initMapState();
});
}
Future<void> fetchItems() async {
itemList = await repository.getItemList();
notifyListeners();
}
Working with multiple asynchronous functions inside Futures depends on whether one is finished or not, not every single one. For this, you can call the "whenComplete" method so you can assure that your future function have finished running. Like this:
For your initMarkers() function:
Future<void> initMarkers() async {
await initPosition().whenComplete((){
Provider.of<Items>(context, listen: false)
.fetchItems();
});
}
For your initMapState() function:
void initMapState() async {
await getCurrentLocation().whenComplete(() async {
await initMarkers().whenComplete((){
setState(() {
_loaded = true;
});
});
});
}
Keep in mind that, in your code, you are not working with the returning value of your getCurrentLocation() function, so instead of using the "then" method use the "whenComplete" method, assuring that you changed or returned your values with this function. Finally, for the initState(), make the function body with asynchronous:
#override
void initState() {
super.initState();
_location.enableBackgroundMode(enable: false);
WidgetsBinding.instance?.addPostFrameCallback((_) async {
initMapState();
});
}
This should work.

type 'Future<List<Appointment>>' is not a subtype of type 'List<Appointment>' in type cast

The error should be clear but I'm unsure how to go around it.
Basically I have a Stream builder I'm calling every second by getData() method to update my SfCalendar with new data.
Stream<DataSource> getData() async* {
await Future.delayed(const Duration(seconds: 1)); //Mock delay
List<Appointment> appointments = foo() as List<Appointment>;
List<CalendarResource> resources = bar() as List<CalendarResource>;
DataSource data = DataSource(appointments, resources);
print("Fetched Data");
yield data;
}
But my appointments method foo() is of type Future<List> and not List.
Future<List<Appointment>> foo() async {
var url0 = Uri.https(
"uri",
"/profiles.json");
List<Appointment> appointments = [];
try {
final response = await dio.get(url0.toString());
//final Random random = Random();
//_colorCollection[random.nextInt(9)];
response.data.forEach((key, value) {
appointments.add(
Appointment(
id: int.parse(
value["id"],
),
startTime: DateTime.parse(value["startTime"]),
endTime: DateTime.parse(value["endTime"]),
),
);
});
} catch (error) {
print(error);
}
return appointments;
}
That is what the error should be telling, yes?
I tried removing the Future cast from foo() appointments but then I can't use async.
I also tried returning Future.value(appointments) but same error.
This is where I call my Stream in initState():
#override
void initState() {
super.initState();
print("Creating a sample stream...");
Stream<DataSource> stream = getData();
print("Created the stream");
stream.listen((data) {
print("DataReceived");
}, onDone: () {
print("Task Done");
}, onError: (error) {
print(error);
});
print("code controller is here");
}
Thank you, please help when possible
Just like JavaScript, async functions always return a Future. That's why you can't use async when you remove Future from the return type.
Since you're not waiting for that Future to resolve, you're actually trying to cast a Future to a List, which isn't a valid cast. All you should need to do is wait for the function to finish so it resolves to a List:
List<Appointment> appointments = await foo() as List<Appointment>;
and, since your return type is Future<List<Appointment>>, you don't actually need to cast the result.
List<Appointment> appointments = await foo();

How to resolve a Future in flutter (dart)?

I want to write a functions which returns until an upload has been finished. If it is possible it would be good if I could also add a timeout.
waitForUpload() async {
uploader.result.listen((result) {
// return waitForUpload
}
}
I just don't find how to write this in dart. To make it more clear: In JS the code would look like this:
async waitForUpload() {
return new Promise((resolve) => {
uploader.result.listen((result) {
resolve();
});
});
}
Using a Completer would be more straightforward.
Future time(int time) async {
Completer c = new Completer();
new Timer(new Duration(seconds: time), (){
c.complete('done with time out');
});
return c.future;
}
Stream.single implements the behavior I want. Looking at implementation, you can see future._complete(result); is called inside the listen method which resolves the future.