Bloc: awaiting async operation from network inside mapEventToState doesn't complete execution

Created on 26 Mar 2019  Â·  30Comments  Â·  Source: felangel/bloc

Hi @felangel , I encounter a weird problem, maybe it is due to my lack of understanding of dart but the following happens to me when i try to fetch a user from the network or the local db inside mapEventToState.Despite awaiting the result of the fetching, the execution seems stopped until i dispatch another calls of the same event to the bloc.Here is the bloc mapEventToState method.

Stream<AuthenticationState> mapEventToState(
      AuthenticationState currentState, AuthenticationEvent event) async* {
    if (event is LoggedOutEvent) {
      yield AuthenticationUninitializedState();
      contrats = null;
      user = null;
    }
    if (event is LoginAttemptEvent) {
      yield AuthenticationLoadingState();
      userRepository = Repository();
      user = await userRepository.fetchUser(event.login, event.password);
      //debugPrint('$loginResult');

      if (user != null) {
        yield AuthenticationAuthenticatedState();
      } else {
        yield AuthenticationUnauthenticatedState();
      }
    }
  }

Here is the fetching process from my repository:

Future<UserModel> fetchUser(String login, String password) async {
    UserModel user;
    var source;
     for (source in sources) {
      if (source is ChapChapNetworkProvider) {
        try {

          final result = await InternetAddress.lookup('google.com');
          if (result.isNotEmpty && result[0].rawAddress.isNotEmpty) {
            user = await source.fetchUser(login, password);
            debugPrint('user is $user');
          }
        } on SocketException catch (_) {
          Fluttertoast.showToast(
              msg:"Aucune connexion internet détectée",
              toastLength:Toast.LENGTH_SHORT,
              gravity:ToastGravity.BOTTOM,
              timeInSecForIos: 1,
              backgroundColor: Colors.grey[300],
              textColor:Colors.black,
              fontSize: 12.0

            );
          debugPrint('no internet connetion');
        }
      } else {
        user = await source.fetchUser(login, password);
        debugPrint('user in db is $user');
      }

      if (user != null) {
        break;
      }
    }
    for (var cache in caches) {
      if (cache != source) {
        //ici les deux sont de meme instance
        cache.storeUser(user);
      }
    }
    return user ?? null;
  }

How can i make the code properly execute and not stop in its tracks? When i dispatch more of the same event execution resumes and completes...

question

Most helpful comment

Hi @felangel ,sorry for the late reply.Understood, ill try debugging first as much as i can on my own and if i cant resolve my issue,ill post the code up and let you know.Have a great day.👍

All 30 comments

Hey @zjjt đź‘‹

Are you able to share the link to the repo or a sample app with the same problem you’re describing? It would be much easier for me to help figure out what’s wrong if I can run the code locally. Thanks! 👍

Alright here is the link to the repo https://github.com/zjjt/chapchap.git
After you clone it be sure to replace hidden_screen_drawer dependency with a link to this git repo https://github.com/zjjt/hidden_drawer_menu.git

try then after clicking on the user menu to login with the following:
Login : CI897887
password:blablabla

for example.Im waiting right there friend.

When i remove the call to the fetchUser method on my repository and put it directly inside the onTap callback the operation completes normally..I would like not to do it from the onTap but instead let the bloc deal with it on a loginAttemptEvent

Thanks I’ll take a look in 15 mins 👍

Great!!

@zjjt sorry for the delay! I just tried taking a look and after a flutter run the app keeps crashing with:

FileSystemException: FileSystemException: Getting current working directory failed, path = '' (OS Error: Too many open files, errno = 24)

Is there something I'm missing in order to be able to run the app? Thanks!

@felangel it might be the hidden_drawer_menu dependency in pubspec.yaml that might be causing the issue.modify the file .in mine i refer to it via relative path. in yours you should refer to it using git to this repo https://github.com/zjjt/hidden_drawer_menu.git

@zjjt I tried both using the git url as well as cloning the hidden drawer menu and using a relative path but both result in the same error being thrown during flutter run.

woow i do not understand...why that is ...are you ok with usign team viewer?

what is team viewer?

It is a software for remote access to another computer.

Do you know of a platform that will let me share my computer screen with you ?

We can use google hangouts. But I won’t be available to get on a call until 12:00 CST. Another option is to strip out all the unnecessary stuff and share a repo that has just the authentication components.

Ok ill try doing that...Ive cloned the repo on my computer and it is working fine on my android emulator...i do not know why it gives an error on yours...just my luck..ill see what i can do and once ready ill provide the link to the new repo here

Hmm 🤔 I was using an iOS simulator. Have you tried on iOS?

Yes on my Ios simulator it cant build for now i have a file not found flutter.h problem.And as android is the first platform i musst deliver the app onto that is why i didnt bother.

I have this problem while building for ios and this is coming from all packages inside my project, even yours it seems it cant find flutter.h.
here is the log:

Xcode's output:
↳
    In file included from
    /Users/macbook/desktop/development/flutter/.pub-cache/hosted/pub.dartlang.org/sqflite-1.1.3/ios/Cla
    sses/SqfliteOperation.m:9:
    /Users/macbook/desktop/development/flutter/.pub-cache/hosted/pub.dartlang.org/sqflite-1.1.3/ios/Cla
    sses/SqfliteOperation.h:7:9: fatal error: 'Flutter/Flutter.h' file not found
    #import <Flutter/Flutter.h>
            ^~~~~~~~~~~~~~~~~~~
    1 error generated.

If you do have an android emulator ,try running the project for android please.

Yeah sure. I’ll give it a try in the next couple of hours. 👍

👍 Thanks a lot Felix

. EDIT please consider using the repo below instead of the previous one

Hi there @felangel , i made the following repo leaving only the important files for analysing the problem.You should not consider my previous message.
https://github.com/zjjt/loginchap.git

Here's also a gif showing you what i am dealing with.You should see that the call to the network do not return unless i dispatch the same event a second time.Thank you for your time.

problem

@zjjt it looks like you aren't properly handling exceptions in your chapchapDb_provider.dart. I wrapped the fetchUser implementation in a try/catch and I caught an error saying the db was null.

That then allowed the code to continue executing repository.dart fetchUser which hangs at final result = await InternetAddress.lookup('google.com');

Looks like all of these issues are unrelated to bloc. I would highly recommend you make sure you handle all exceptions that can occur in your code otherwise you'll run into issues like this.

Hope that helps and sorry for the delayed response!

@felangel Thanks for taking the time to answer and also taking a look into it.
ill do as you say....thanks a lot

@zjjt no problem! You might want to set timeouts for async code and if the code takes too long just return an error. That way you'll avoid having situations where code is just hanging and from the user's perspective it looks like nothing is happening.

Closing this for now but feel free to comment with additional questions and I'm happy to reopen it/continue the conversation. 👍

👍Tanks a lot @felangel ill do so and properly check the code.After wrapping the call to fetchuser with a try catch as you said everything ran fine....I Learned today that any code susceptible to misbehave should be handled correctly...If you ever visit West Africa one day i wish you could come to Ivory Coast i shall be your host and treat you to the local delicacies

Hi @felangel, i hope you are doing fine my friend.I have a quick question for you.Does a bloc notice when when the same state comes but with a different parameter?
To illustrate let's say i have LoginState(isLogged:false) as first returned state and soon after without changing the state i dispatch an event this time producing the state LoginState(isLogged:true).

I noticed the bloc seems to ditch this kind of practice.

Hey @zjjt đź‘‹

By default the bloc will notice anytime you yield a new state instance. If you’re extending Equatable or overriding hashCode and == then you need to make sure you’re differentiating the states based on the different properties. Hope that helps!

If you’re still confused or have questions it would be great if you could share some sample code that I can run locally and I can try to help resolve any issues you’re running into more quickly. Thanks! 👍

Hi @felangel ,sorry for the late reply.Understood, ill try debugging first as much as i can on my own and if i cant resolve my issue,ill post the code up and let you know.Have a great day.👍

Sounds good and thanks, you too!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

fvisticot picture fvisticot  Â·  31Comments

mariaszek9003 picture mariaszek9003  Â·  29Comments

hahai96 picture hahai96  Â·  40Comments

realtebo picture realtebo  Â·  41Comments

endigo picture endigo  Â·  34Comments