Flutter Await for websocket response - flutter

Solved
I've solved this problem using a Future function and using Completer inside the function.
I am getting some Images from my server with websockets.
I have a function that emits an event with the name of the image that I need and sends an event with the Image, that is working fine, but I need my App to wait for the return of my function because my app is calling the function and trying to go to the next page without the image.
Can someone explain to me how can I make my app wait for my function to return ?
Update
I am using Stream Builder now but I can't return the data from my function.
Stream<List> getFile(List imageL) async*{
if(imageL.isNotEmpty){
List downloadedData = List();
socket.emit("PostsImagem", (imageL));
socket.on("ImagemPost", (dados) {
downloadedData = dados;
imageL = List();
});
//I can't return the downloadedData because is inside the //socket.on()
}
}

Related

Future Builder doesn't update view always

I have a future builder, and Im using two future variables:
Future<List<Notifications>>? notificationsOfTheDay; //get saved notifications from db
Future<List<NotificationCategory>>? notificationsByCat; // sort/modify "notificationsOfTheDay"
I'm sending notificationsByCat to Future Builder.
The issues:
While the app starts, the future builder is able to receive all the notifications and manipulate the data with some asynchronous operations.
But sometimes the Future Builder displays blank.
I'm also appending received notifications to the existing Future Variable notificationsOfTheDay, when sometimes the view does not update.
Code snippets are listed below:
Here is my initState
void initState() {
super.initState();
initPlatformState(); // Notification Listener Service
notificationsOfTheDay = initializeData(isToday);
}
initilizeData Method
Future<List<Notifications>> initializeData(bool istoday) async {
notificationsOfTheDay = initializeNotifications(istoday);
if (notifications!.length > 0) {
notificationsByCat = notificationsByCategory(notificationsOfTheDay); //sorting/manipulation of existing future
}
return notifications!;
}
notificationsByCategory
Future<List<NotificationCategory>> notificationsByCategory(
List<Notifications> notificationsFuture) async {
return await NotificationsHelper.getCategoryListFuture(
isToday ? 0 : 1, notificationsFuture);
}
When any new notifications are received, it is inserted into the db and the exising future is appended with the new notification;
setState(() {
notificationsOfTheDay =
appendElements(notificationsOfTheDay!, _currentNotification!);
notificationsByCat = notificationsByCategory(notifications!);
});
Future<List<Notifications>> appendElements(
Future<List<Notifications>> listFuture,
Notifications elementToAdd) async {
final list = await listFuture;
list.add(elementToAdd);
return list;
}
Can anyone please guide me to a solution? Tried many combinations. If I'm directly showing the data without modifying it according to category, it works fine.
Where am I going wrong?

How to handle reading from database when API-request hasn't finished yet to save to database in Flutter?

For my App i'm loading the link for the background-image for each screen from my API.
Right after the query that downloads and saves the image-link, i'm querying the link from the database.
The problem now is, that the function isn't waiting for the download and saving to finish although i'm using await, therefor i get an empty result from the database and get an error from the imageloader.
Future<String> downloadAsset(String name) async {
final Map<String, String> _json = {
'mandant': Config.mandant,
'name': name
};
final query = MakePost('get_app_assets', false, _json, saveAsset);
await query.queryAPI(); // Function won't wait for this to finish
String ret = await dbAppAssets.getText(name); // Get link from database
return ret;
}
I've already tried to use .then(), but the same thing happens.
This only happens initially on the first call of each screen, but how is this normally beeing handled?
I'm using riverpod with futureProviders if that matters.
I do not know where you are using the downloadAsset function, but when you use Future on a function you should also await the function where you are using it, for example:
Future<void> _reverseScrollToTopAnimation() async {
await controller!.reverse();
_showBackToTopButton = false; // hide the back-to-top button
}
then, wherever you call it you should also await that function:
await _reverseScrollToTopAnimation();
If not the function will act as a synchronous operation even though you are using await inside the function.

in Flutter, make a list of api call inside one api call

In one of my flutter app, at first I want to call an api, which will return a list of item, and the item will be shown in a ListView. I also need to call another api for each item of the ListView to fetch description of that item and show the description to each item according to their id. How can I resolve this scenario. In RxJava, there is an operator called flatmap which did the same things without any hassle. But in flutter, How can I implement this. Here is my 2 function
class HomeRepositoryImpl extends HomeRepository {
HomeGraphQLService homeGraphQLService;
HomeMapper homeMapper;
HomeRepositoryImpl(HomeGraphQLService homeGraphQLService, HomeMapper homeMapper) {
this.homeGraphQLService = homeGraphQLService;
this.homeMapper = homeMapper;
}
#override
Future<List<Course>> getAllCourseOf(String className, String groupName) async {
final response = await homeGraphQLService.getAllCourseOf(className, groupName);
return homeMapper.toCourses(response).where((course) => course.isAvailable);
}
#override
Future<CourseProgressAndPerformance> getProgressAndPerformanceAnalysisOf(String subjectCode) async {
final response = await homeGraphQLService.getProgressAndPerformanceAnalysisOf(subjectCode);
return homeMapper.toProgressAndPerformance(response);
}
}
In the above class, first I call getAllCourseOf() function to get a list of course and show them in list view. I need to call getProgressAndPerformanceAnalysisOf(courseId) to fetch description of each item and show the description in each item of that list.
So what is recommended way to do so.
thanks in advance
I'm not sure on how the listing would be presented, my guess is you're looking for Stream and asyncMap()
Here's an example implementation that would give you a list of CourseProgressAndPerformance, this is the direction I'd investigate.
var perfList = Stream
.fromIterable(listOfCourses)
.asyncMap((course) => getProgressAndPerformanceAnalysisOf(courseId))
.toList();

Flutter: issue with Future which block a function

I am currently developping a flutter application with Dart. I want to add some local notification when there is something new.
For that I'm using a periodic task with workmanager, which make a http request to check the last "news". The issue here is that the function stop at client.get()
Future<List<String>> _grepLastNews() async {
var client2 = new http.Client();
debugPrint("here");
//issue below
final response =
await client2.get('http://..../lireLastNews.php').timeout(Duration(seconds: 4));
client2.close();
debugPrint("here 2");
var body;
if (response.statusCode == 200) {
body = jsonDecode(response.body);
} else {
return ["0","0"];
}
return jsonDecode(body);
}
Here you can find the output:
output
You can see it stop before the second checkpoint... I have tried with and without timeout, with changing the name of the other http client of the application but nothing work. I must add that I have an other http client which work perfectly ( but not in background ^^).
Thanks for helping me
EDIT: I tried with
await Future.delayed(Duration(seconds: 2),() => ["0","0"]);
but the output is the same so the issue is not with http.get but about the future which I don't know why stop there.
EDIT 2: In fact in an async function I tried
debugPrint("here 2");
await Future.delayed(Duration(seconds: 2));
debugPrint("here 3");
and it never go for "here 3".
EDIT 3:
I tried differents variant using Future.wait([_grepLastNews()]); but it don't work: it continue until raising an error because of the null result of _grepLastNews().

How can I asynchronously stream loaded objects from a list of futures in Dart

I have a list of objects that can be loaded by calling the function object.load().
This function returns a loaded version of the same object asynchronously.
I want call the load() funcion of all objects in a list at the same time and stream the loaded versions as soon as they finish loading.
The code below works but the program is loading one object at a time.
Sender:
Stream<ImageIconModel> streamLoadedIcons() async* {
for (var i = 0; i < imageIconModels.length; i++) {
yield await imageIconModels[i].load().then((loadedIconModel) {
return loadedIconModel;
});
}
}
Receiver:
await for (var loadedIcon in streamLoadedIcons()) {
final var result = doSomething(loadedIcon);
yield result;
}
The main problem is:
In the sender, if I await each load() call, it will do every step in the loop awaiting the load() to finish.
But if I remove the "await", I would be returning a future, not the loaded icon.
You need Stream.fromFutures.
final loadedIconModelStream = Stream.fromFutures([
for (final iconModel in imageIconModels) iconModel.load(),
]);
Both #hacker1024 an #pskink answers successfully answered my question!
But neither one worked as it supposed to and I think I discovered why.
I substituted the load() method for a Future.delayed(duration: random), and then the program worked as it intended to.
So what I think happened is that probably the lib I'm using to load the images (multi_image_picker: ^4.7.14) is accessing the phone files synchronously.
So even if I try to load every image at same time, it will do the task synchronously and return every image at the order I called them to load.
Thank you both for the answer!