Bloc: Bloc calls closes everytime I switch between tabs or Navigator.pop

Created on 5 Mar 2020  ·  7Comments  ·  Source: felangel/bloc

Describe the bug
I have a bloc that I'm providing with BlocProvider.value on top of MaterialApp.
I believe it shouldn't be disposed automatically.

I need to get this bloc in two different tabs(BottomNavigationBar). When I switch to tab#3 from tab#2 and then back to tab#2, I've noticed bloc calls close method and then this feature relies on bloc doesn't work.

Also I have a button which shows dialog. With this dialog, I'm sending event to bloc, it works for the first time but then when I open the dialog again, it doesn't work. I've debugged and noticed it calls close() again. I find it very odd.

To Reproduce
Repo of the small portion of the app: https://github.com/mirkancal/bloc_issue

  1. Switch back to tab#2 from tab#3
    (I couldn't reproduce this in my example app)
    or
  1. Open and close the dialog on tab#3. It works once.
    That issue remains. When I open the dialog and go back, it closes the bloc.

Expected behavior
I expect bloc to not to get disposed.

Screenshots
This is a tab to change the current market. I add an event when user taps any rows. Like SelectPair(pair: currentPair).

This way I can change the current market on this tab.

Also I can open dialog, which shows a little version of Market tab. Users can change the pair(like BTC/USDT) with same event, SelectPair.

*Logs *
flutter analyze shows unused variables and imports.

Here's the doctor -v output:

[✓] Flutter (Channel stable, v1.12.13+hotfix.8, on Linux, locale en_US.UTF-8)
    • Flutter version 1.12.13+hotfix.8 at /home/mirkan/development/flutter
    • Framework revision 0b8abb4724 (3 weeks ago), 2020-02-11 11:44:36 -0800
    • Engine revision e1e6ced81d
    • Dart version 2.7.0


[✓] Android toolchain - develop for Android devices (Android SDK version 28.0.3)
    • Android SDK at /home/mirkan/development/Android/
    • Android NDK location not configured (optional; useful for native profiling
      support)
    • Platform android-28, build-tools 28.0.3
    • ANDROID_HOME = /home/mirkan/development/Android/Sdk
    • ANDROID_SDK_ROOT = /home/mirkan/development/Android/Sdk
    • Java binary at: /opt/android-studio/jre/bin/java
    • Java version OpenJDK Runtime Environment (build
      1.8.0_202-release-1483-b49-5587405)
    • All Android licenses accepted.

[!] Android Studio (version 3.5)
    • Android Studio at /opt/android-studio
    ✗ Flutter plugin not installed; this adds Flutter specific functionality.
    ✗ Dart plugin not installed; this adds Dart specific functionality.
    • Java version OpenJDK Runtime Environment (build
      1.8.0_202-release-1483-b49-5587405)

[✓] IntelliJ IDEA Ultimate Edition (version 2019.3)
    • IntelliJ at /snap/intellij-idea-ultimate/204
    • Flutter plugin version 43.0.3
    • Dart plugin version 193.6015.53

[✓] VS Code (version 1.42.1)
    • VS Code at /usr/share/code
    • Flutter extension version 3.8.1

[✓] Connected device (1 available)
    • Eight • 192.168.60.101:5555 • android-x86 • Android 8.0.0 (API 26)

! Doctor found issues in 1 category.


question

Most helpful comment

@RollyPeres thanks! I was able to solve my issue just by your answer. I see that I use lots of antipatterns. Still didn't understand what solved my problem but I guess using BlocProvider to provide same bloc for many times caused the issue.

All 7 comments

@mirkancal Would be a lot easier for people to help you out if you could share a minimal app which reproduces your problem.

Hi @mirkancal 👋
Thanks for opening an issue!

As @RollyPeres mentioned, it would be great if you could provide the link to a sample app which illustrates the problem. Thanks! 👍

Thanks for replying so fast. I've added the repo of the small portion of the app.

https://github.com/mirkancal/bloc_issue

@mirkancal That's not really a small app reproducing your bug. Please strip down everything that is not related to your problem and upload a main.dart that is easily runnable. And who knows, you might actually find your problem by cleaning up unnecessary stuff.

@RollyPeres well I have removed all the http and socket connections, logins and data persistency stuff, other blocs, other unnecessary tabs and other functionalities. I don't know what else to strip down. The problem occurs within two tabs and one dialog so I leave them purposely.

Also I wanted to use exactly the same bloc which changes the current cryptocurrency to display, so I had to add those data by mocking http call.

Do you want me to use different setup and concept to reproduce? Let me know what else you want me to remove.

@mirkancal First of all you should not keep Pair currentPair; on your bloc. That's state inside bloc and that's an anti-pattern; keep all your state in your state class/es.

Secondly, when consuming a bloc just do it like: BlocBuilder<PairSwitchBloc, PairSwitchState> without explicitly passing in bloc: _pairSwitchBloc. Same goes for listener. Just let it be retrieved automatically based on runtimetype.

Here you're creating a new bloc every single time you're opening the dialog:

_pairSwitchDialog(BuildContext context) async {
    await showDialog<String>(
      context: context,
      builder: (context) {
        return Center(
          child: BlocProvider(
            create: (context) => _pairSwitchBloc,
            child: MarketSelect(),
          ),
        );
      },
    );
  }

You probably want:

_pairSwitchDialog() async {
    await showDialog<String>(
      context: context,
      builder: (_) {
        return Center(
          child: BlocProvider<PairSwitchBloc>.value(
            value: BlocProvider.of<PairSwitchBloc>(context),
            child: MarketSelect(),
          ),
        );
      },
    );
  }

Please notice that you don't need to pass the BuildContext to your method since your method is inside the state class and so you have access to the context already which is nothing but a property on the state class BuildContext get context => _element;.
Be aware that if your bloc is not provided on top of MaterialApp, the builder from showDialog is not going to have access to your bloc, since it gives you a different context compared to the one from state.

This is what I noticed at a first glance, kinda caught up, but these notes should put you on the right track. Feel free to come back if you still encounter issues.

@RollyPeres thanks! I was able to solve my issue just by your answer. I see that I use lots of antipatterns. Still didn't understand what solved my problem but I guess using BlocProvider to provide same bloc for many times caused the issue.

Was this page helpful?
0 / 5 - 0 ratings