Flutter multi threading save file to local - flutter

for(var item in list)
{
var body = (await api.get(item.url)).bodyBytes;
await file.writeAsBytes(body);
}
How can I change this code to multi threading. This code is very slow. Any examples?

It's slow because you're forcing your application to wait for every api request and every file write before starting the next iteration.
Start every request at the same time and wait for them all simultaneously. Multithreading will not speed up tasks that are just slow and it would not be practical in Dart.
await Future.wait(list.map((item) async {
var body = (await api.get(item.url)).bodyBytes;
await file.writeAsBytes(body);
}));
Or with a more verbose, but maybe clearer syntax:
List<Future> futures = [];
for(var item in list) {
futures.add(Future(() async {
var body = (await api.get(item.url)).bodyBytes;
await file.writeAsBytes(body);
}));
}
Future.wait(futures);
I'm not really sure why you're doing await file.writeAsBytes(body); with the same file every iteration, but it appears to be a mistake to me. Just be aware.

Related

How can I send multiple async requests in Flutter that is not just concurrent but parallel?

I am calling a TTS API for multiple lines of texts. Ideally I would like to have them executed in parallel, meaning that one request would not wait for the other to finish before starting, hence speeding up total runtime of the API calls.
Here is an excerpt from my code:
await Future.forEach(rounds, (round) async {
await _fetchAudioForText(
round, voiceA );
totalBytes += round.audio?.lengthInBytes ?? 0;
});
...
Future<bool> _fetchAudioForText(Round round, Voice voice) async {
round.audio =
await ttsUtils.getAudioByteStream(round.text, voice);
return true;
}
getAudioByteStream is essentially calling the TTS API using a HTTP request and has a return type of a byte stream (Uint8List).
The problem is, that it's not actually doing it in parallel. What am I missing here?
remove await in forEach
await Future.forEach(rounds, (round) async {
_fetchAudioForText(
round, voiceA );
totalBytes += round.audio?.lengthInBytes ?? 0;
});

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.

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 to perform Async await in the below code

I need clarifications about how to solve the below code using async and await and future API in dart.
void main()
{
print("Program starts");
printdart(1);
print("Program finishes");
}
printdart(int temp)
{
int i;
for(i=temp;i<=1000;i++)
{
print("dart");
if(i%10==0)
{
printangular(i+1);
break;
}
}
}
printangular(int temp)
{
int i;
for(i=temp;i<=1000;i++)
{
print("angular");
if(i%10==0)
{
printdart(i+1);
break;
}
}
}
How to implement async and await in dart
I think you need to study more how Dart deals with Threads. I can't explain everything here, but basically Dart runs only one Thread, so all your code will just block that Thread, async awit won't help you.
Dart also have Isolates, that can run in multiple threads, but since they are very isolated, it's not easy to pass and get data from them.
Async/await works best with network requests and file access, because they block once activated, so the Thread can just ignore them for now and go back there when there's a new value. Your code in the other hand doesn't block, so you can't await for it.
There's one way though, you need to refractor your code so it will yield values, and you can async await them. In this case you need to read about Async Generators and see how they work so you can reformat your code accordingly.
In the code you provided, there is no waiting for the code to do some heavy process.
Below is a modified version of your code. Here, the code will wait for some time before it is called again. In the meantime rest of the code is executed.
import 'dart:async';
void main() {
print("Program starts");
printdart();
printangular();
print("Program finishes");
}
printdart() async {
int i;
for (i = 1; i <= 4; i++) {
print("dart");
await Future.delayed(const Duration(seconds: 2));
}
}
printangular() async {
int i;
for (i = 1; i <= 4; i++) {
print("angular");
await Future.delayed(const Duration(seconds: 1));
}
}
To answer your question:
async: a keyword to tell the compiler that the function will take some time to complete but in the meantime, go back and run the next part of the program and come back when this function is done.
await: this allows waiting for the process to complete before jumping to immediate next line.

Protractor tests are inconsistent even with browser.wait and helper functions

I am looking for some advice. I have been using protractor for a few weeks and just cannot get my tests to be consistent unless I use browser.sleep. I have tried helper functions as well as browser.wait(expectedCondition). I have reduced browser.sleep immensely, but protractor still just goes way to fast. I can never successfully run multiple tests unless I have a few browser.sleeps just so protractor can relax for a second. Here is an example:
The Test I need to select a user, delete that user and wait for a success message. Then I click the same user and click the activate button.
Outcome: Unless I have browser.sleep, my success messages do not even appear after deletion/activation. The tests fail because protractor is moving way too fast. Even with the expected conditions. My main problem is that protractor moves to fast for the angular web page. I have tried ifCLickable or isDisplayed but they do not fix the issue entirely. Here is the code:
async deleteUser() {
await sendClick(this.getNewUser());
await sendClick(this.getDelete());
await waitTillPresent(this.getDeleteConfirm());
await sendClick(this.getDeleteConfirm());
await waitTillPresent(this.getSuccessMsg())
expect(await page.getSuccessMsg().isDisplayed()).toBeTruthy();
}
async activateUser() {
await sendClick(this.getNewUser());
await waitTillPresent(this.getEditBtn())
await sendClick(this.getActive());
await waitTillPresent(this.getSuccessMsg())
expect(await page.getSuccessMsg().isDisplayed()).toBeTruthy();
}
Functions:
export async function sendClick(element: ElementFinder): Promise<boolean> {
try {
if(!await element.isDisplayed()) {
return false;
}
await browser.executeScript('arguments[0].click();', await element.getWebElement());
return true;
}
catch (err) {
return false;
}
}`
export async function waitTillPresent (element: ElementFinder, timeout: number = 10000) {
return browser.wait(() => {
return element.isPresent();
}, timeout);
}
My Question: Am I handling this correctly? Is there a better to ensure my tests are consistent? Before these tests, I visit a non-angular webpage. So I have to include the line browser.waitForAngularEnabled(false)
Does this mess with the async nature of angular? Thank you.
I worked the last few months on our e2e test suite to make it stable. I did not believe it's possible but I made it using correct wait functions and sometimes browser.sleep() as a last resort.
You have a correct approach for waiting for elements. But there are 2 problems regarding your implementation:
1) The function waitTillPresent() does exactly what its name stands for. But if you only wait until the element is present on the page it does not mean it's clickable or displayed. An element can be hidden and at the same time still be present. Please rename waitTillPresent() to waitTillDisplayed() and change it as follows:
export async function waitTillDisplayed(element: ElementFinder, timeout: number = 20000): Promise<boolean> {
let result = await browser.wait(() => element.isPresent(), timeout);
if(!result) {
return false;
}
return await browser.wait(element.isDisplayed(), timeout);
}
2) You should exceed the default timeout. Set it a bit higher like 20 to 25 seconds. Just play with it.
Unfortunately, I don't know how browser.waitForAngularEnabled(false) changes test behavior. We do not use it :)
Note:
These functions are all exactly the same:
function foo() { return 'hello world'; }
var foo = () => { return 'hello world'; };
var foo = () => 'hello world';
Play with arrow functions, it's syntactic sugar.
Cheers and gl!