Why do I need to run a function with if-statements multiple times to reach other statements? - flutter

void _checkbothloc(BuildContext context) {
if (_permissionGranted != PermissionStatus.GRANTED) {
_requestPermission();
} else if (_serviceEnabled != true) {
_requestService();
} else {
_takePicture(context);
}
}
Why do I have to run _checkbothloc 3 times to get to _takePicture(context)?
Does anyone have the same problem and have found a solution?

_takePicture is only reached the third time because you are using else / else if blocks. Instead, you would want to set up your function without them:
void _checkbothloc(BuildContext context) {
if (_permissionGranted != PermissionStatus.GRANTED) {
_requestPermission();
}
if (_serviceEnabled != true) {
_requestService();
}
_takePicture(context);
}
This way the conditions do not depend on each other and will both run no matter what. This also means that _takePicture will always be run, just sometimes the permission needs to be requested before and sometimes the service needs to be requested before.
Learn more about control flow statements in Dart.
You also need to ensure that _requestPermission and _requestService do not run asynchronously. If that is the case, mark your function as async and await these.
Learn more about asynchronous programming in Dart.

Related

Is it good approach to cancel WorkManger task in executeTask() function in flutter

I have to cancel/dispose workmanager task as soon as it gets completed, but most of the times app is not in running state. So is it good or bad to cancel that task in executeTask() function.
Here is code example:
Register task first
Workmanager().registerOneOffTask('taskABC','taskABC',
inputData: {'data':'some data here'},);
And here is an code inside callbackDispathcer()
Workmanager().executeTask((taskName, inputData) async {
try {
switch(taskName) {
case 'taskABC':
//do something here
Workmanager().cancelByUniqueName('taskABC');
break;
}
return true;
} catch(e) {
debugPrint('---> Error in work manager execution taskName[$taskName] with inputData[$inputData] | Exception: $e');
return false;
}});
I just need to know what could be the best way to cancel/dispose a task, when the app is not in running state.

why the dart function did not return the sub function result

I am now using this functon to fetch new music in flutter:
class QuietPlayQueueInterceptor extends PlayQueueInterceptor {
#override
Future<List<MusicMetadata>> fetchMoreMusic(BackgroundPlayQueue queue, PlayMode playMode) async {
if (queue.queueId == kFmPlayQueueId) {
final musics = await (neteaseRepository!.getPersonalFmMusicsFromQueue() as FutureOr<List<Music>>);
final musicListExt= musics.toMetadataList();
return musicListExt;
}
return super.fetchMoreMusic(queue, playMode);
}
}
and this is the function getPersonalFmMusicsFromQueue define:
Future<List<Music>?> getPersonalFmMusicsFromQueue() async {
if(fmPlayQueue.isEmpty){
return getPersonalFmMusics();
}else{
final Music music = fmPlayQueue.first;
final List<Music> musics = List.empty(growable: true);
musics.add(music);
return Future.value(musics);
}
}
what makes me confusing is that the getPersonalFmMusicsFromQueue function did not return any result. I make a breakpoint on the line final musicListExt= musics.toMetadataList(); but did not hited. The console is no error output. where am I doing wrong? what should I do to fix this problem?
getPersonalFmMusics looks asynchronous? Perhaps you're not awaiting
Future<List<Music>?> getPersonalFmMusicsFromQueue() async {
if(fmPlayQueue.isEmpty){
return await getPersonalFmMusics();
}
// ...
I would also advise against casting unless you're sure you need it. Instead, have the return type of getPersonalFmMusicsFromQueue return a FutureOr
(neteaseRepository!.getPersonalFmMusicsFromQueue() as FutureOr<List<Music>>); // Remove FutureOr<List<Music>>
// and make the function signature instead look like this:
FutureOr<List<Music>> getPersonalFmMusicsFromQueue(); // Force unwrapping with a `!` but also throwing proper exceptions when null.
The reason being is that casting usually hides errors the compiler would otherwise be warning you about.
Another idea I have if the above isn't the issue is the .first call.
final Music music = fmPlayQueue.first;
If this is a first getter on a stream then that need to be awaited and it likely isn't working because it's just indefinitely waiting for the stream to output a value.

Getting an error when everything's supposed to work

I'm building an app with Flutter where you can add files to the app's cache.
There are 2 things that are not working, which I don't understand why.
Here's the source
Whenever I launch the app for the first time (with absolutely no cache) I get this error
Directory listing failed, path = '/data/user/0/com.example.lockedapp/cache/file_picker/' (OS Error:
No such file or directory, errno = 2)
Even though I made precautions to create the directory before trying to display it.
bool checkFilesEmpty() {
var cache = new Directory('/data/user/0/com.example.lockedapp/cache/file_picker');
cache.exists().then((resp) => { if (!resp) { cache.create() } }); // creates a new cache directory if it does not exist
return cache.listSync(recursive: false).toList().length != 0; // returns false if it's empty
}
on line 31, the checkFilesEmpty is checked first and then comes everything else, but i still get the error.
the weird thing is that if I relaunch the app, it works as it's intended.
Any solutions for this? I'm really confused
Put your checkFilesEmpty in initState method of Stateful widget hence it will be called on before your widget is building.
class MyHomeState extends State<MyHome> {
bool filesEmpty;
#override
void initState() {
super.initState();
filesEmpty = checkFilesEmpty();
}
.
. // Your rest of code
.
}
You can put your error causing statement in try catch block. If there is no listing then you can create one in catch block:
bool checkFilesEmpty() {
try{
var cache = new Directory('/data/user/0/com.example.lockedapp/cache/file_picker');
return cache.listSync(recursive: false).toList().length != 0;
}
catch{
cache = Directory('/data/user/0/com.example.lockedapp/cache/file_picker').create() ;
return cache.listSync(recursive: false).toList().length != 0;
}
}

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!