felangel / bloc

A predictable state management library that helps implement the BLoC design pattern
https://bloclibrary.dev
MIT License
11.83k stars 3.4k forks source link

Event triggered before splash screen on v0.18.0, but 0.17.0 is fine. #586

Closed devibrahimkarahan closed 5 years ago

devibrahimkarahan commented 5 years ago

I'm checking session on splash screen, if user logged before, I'm redirect user to main screen, otherwise redirect to login page. But after rerun app, bloc yield state before splash build.

Problem occurs in version >= 0.18.0, No problem with versions 0.17.0 and below

When i open the app after first opening (install > first open (no problem) > close and rerun (problem occurs now)) AppStarted event triggered before splash build, because of this i cant redirect user login page or main page.

main.dart

void main() {
  //Device oriantation is always up
  SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp])
      .then((_) {
    BlocSupervisor.delegate = SimpleBlocDelegate();
    runApp(App());
  });
}
class App extends StatefulWidget {
  App({Key key}) : super(key: key);

  @override
  State<App> createState() => _AppState();
}

class _AppState extends State<App> {
  final BlocLocalization blocLocalization = BlocLocalization();
  final BlocTheme blocTheme = BlocTheme();
  final AuthenticationBloc blocAuth = AuthenticationBloc();
  Brightness currentBrightness;
  Locale currentLocale;

  @override
  void initState() {
    final router = Router();
    AppRouter.configureRoutes(router);
    AppConfig.router = router;
    Log.init();
    BlocTheme.updateStatusBar();
    currentBrightness = blocTheme.initialState;
    blocAuth.dispatch(AppStarted());
    super.initState();
  }

  @override
  void dispose() {
    AppConfig.router = null;
    AppTheme.brightness = null;
    blocTheme.dispose();
    blocLocalization.dispose();
    blocAuth.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return BlocProviderTree(
      blocProviders: [
        BlocProvider<BlocTheme>(
          builder: (_) => blocTheme,
        ),
        BlocProvider<BlocLocalization>(
          builder: (_) => blocLocalization,
        ),
        BlocProvider<AuthenticationBloc>(
          builder: (_) => blocAuth,
        ),
      ],
      child: BlocListenerTree(
        blocListeners: [
          BlocListener(
            bloc: blocTheme,
            listener: (_, brightness) {
              setState(() => currentBrightness = brightness);
            },
          ),
          BlocListener(
            bloc: blocLocalization,
            listener: (_, locale) {
              setState(() => currentLocale = locale);
            },
          ),
        ],
        child: MaterialApp(
          debugShowCheckedModeBanner: false,
          onGenerateRoute: AppConfig.router.generator,
          theme: ThemeData(
            appBarTheme: AppBarTheme(brightness: currentBrightness),
            brightness: currentBrightness,
            fontFamily: 'OpenSans',
          ),
          locale: currentLocale,
          supportedLocales: [
            Locale('en', 'US'),
            Locale('tr', 'TR'),
          ],
          localizationsDelegates: [
            AppLocalization.delegate,
            GlobalMaterialLocalizations.delegate,
            GlobalCupertinoLocalizations.delegate,
            GlobalWidgetsLocalizations.delegate,
          ],
          localeResolutionCallback: (locale, supportedLocales) {
            // Null control for iOS
            if (locale == null) {
              blocLocalization.dispatch(SupportedLanguage.EN);
              return supportedLocales.first;
            }
            if (supportedLocales.any((supportedLocale) =>
            supportedLocale.languageCode == locale.languageCode &&
                supportedLocale.countryCode == locale.countryCode)) {
              if (locale == Locale('tr', 'TR'))
                blocLocalization.dispatch(SupportedLanguage.TR);
              else if (locale == Locale('en', 'US'))
                blocLocalization.dispatch(SupportedLanguage.EN);
              return locale;
            }
            blocLocalization.dispatch(SupportedLanguage.EN);
            return supportedLocales.first;
          },
        ),
      ),
    );
  }
}

My authentication bloc

class AuthenticationBloc
    extends Bloc<EventAuthentication, StateAuthentication> {
  static final AuthenticationBloc _singleton = AuthenticationBloc._();

  AuthenticationBloc._();

  factory AuthenticationBloc() => _singleton;

  @override
  StateAuthentication get initialState => AuthenticationUninitialized();

  @override
  Stream<StateAuthentication> mapEventToState(
      EventAuthentication event) async* {
    if (event is AppStarted) {
      print("appstarted event");
      SharedPreferences pref = await SharedPreferences.getInstance();
      if (pref.getString("token") != null) {
        print("Shared Prefs isNot Null");
        HttpManager.cookie = pref.getString("cookie");
        HttpManager.token = pref.getString("token");
        HttpManager.userId = pref.getInt("userId");
        yield AuthenticationAuthenticated();
      } else {
        print("Shared Prefs is Null");
        yield AuthenticationUnauthenticated();
      }
    }

    if (event is LoggedIn) {
      yield AuthenticationAuthenticated();
    }

    if (event is LoggedOut) {
      //
    }
  }
}

Splash page ( root )

class PageSplash extends StatefulWidget {
  static const String PATH = "/";

  @override
  _PageSplashState createState() => _PageSplashState();
}

class _PageSplashState extends State<PageSplash> {
  @override
  Widget build(BuildContext context) {
    print("build splash");
    return BlocListener(
      bloc: BlocProvider.of<AuthenticationBloc>(context),
      listener: (context, state) {
        print("splash state: $state");
        if (state is AuthenticationUnauthenticated) {
          AppConfig.router.navigateTo(
            context,
            PageLogin.PATH,
            clearStack: true,
          );
        }
        if (state is AuthenticationAuthenticated) {
          AppConfig.router.navigateTo(
            context,
            PageMain.PATH,
            clearStack: true,
          );
        }
      },
      child: Scaffold(
        backgroundColor: AppTheme.of().colorPageBackground,
        body: Center(
          child: Text("Splash Screen"),
        ),
      ),
    );
  }
}

Logs when first opening after install As you can see, after checking session, bloc triggered AuthenticationUnauthenticated after build splash, this is what i want.

Installing build\app\outputs\apk\app.apk...
Syncing files to device Android SDK built for x86...
I/flutter (27350): AppStarted
I/flutter (27350): SupportedLanguage.TR
I/flutter (27350): appstarted event
I/flutter (27350): Transition { currentState: en_US, event: SupportedLanguage.TR, nextState: tr_TR }
I/flutter (27350): SupportedLanguage.TR
I/flutter (27350): build splash
D/EGL_emulation(27350): eglMakeCurrent: 0xa9584240: ver 2 0 (tinfo 0xa9583270)
I/flutter (27350): Shared Prefs is Null
I/flutter (27350): Transition { currentState: AuthenticationUninitialized, event: AppStarted, nextState: AuthenticationUnauthenticated }
I/flutter (27350): splash state: AuthenticationUnauthenticated
I/flutter (27350): SupportedLanguage.TR
I/flutter (27350): SupportedLanguage.TR
I/zygote  (27350): Do partial code cache collection, code=60KB, data=42KB
I/zygote  (27350): After code cache collection, code=60KB, data=42KB
I/zygote  (27350): Increasing code cache capacity to 256KB

And now when i restart app As you can see, AuthenticationUnauthenticated state triggered before build splash.

Restarted application in 5,254ms.
I/flutter (27350): AppStarted
I/flutter (27350): SupportedLanguage.TR
I/flutter (27350): appstarted event
I/flutter (27350): Transition { currentState: en_US, event: SupportedLanguage.TR, nextState: tr_TR }
I/flutter (27350): SupportedLanguage.TR
I/flutter (27350): Shared Prefs is Null
I/flutter (27350): Transition { currentState: AuthenticationUninitialized, event: AppStarted, nextState: AuthenticationUnauthenticated }
I/flutter (27350): build splash
I/flutter (27350): SupportedLanguage.TR
I/flutter (27350): build splash

flutter doctor -v

[√] Flutter (Channel stable, v1.9.1+hotfix.4, on Microsoft Windows [Version 10.0.18362.418], locale en-US)
    • Flutter version 1.9.1+hotfix.4 at C:\src\flutter
    • Framework revision cc949a8e8b (3 weeks ago), 2019-09-27 15:04:59 -0700
    • Engine revision b863200c37
    • Dart version 2.5.0

[√] Android toolchain - develop for Android devices (Android SDK version 29.0.2)
    • Android SDK at C:\Users\Karahan\AppData\Local\Android\sdk
    • Android NDK location not configured (optional; useful for native profiling support)
    • Platform android-29, build-tools 29.0.2
    • Java binary at: C:\Program Files\Android\Android Studio\jre\bin\java
    • Java version OpenJDK Runtime Environment (build 1.8.0_152-release-1343-b01)
    • All Android licenses accepted.

[√] Android Studio (version 3.4)
    • Android Studio at C:\Program Files\Android\Android Studio
    • Flutter plugin version 38.2.1
    • Dart plugin version 183.6270
    • Java version OpenJDK Runtime Environment (build 1.8.0_152-release-1343-b01)

[√] IntelliJ IDEA Community Edition (version 2019.2)
    • IntelliJ at C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2019.1.3
    • Flutter plugin version 40.1.4
    • Dart plugin version 192.6817.14

[√] VS Code (version 1.39.2)
    • VS Code at C:\Users\Karahan\AppData\Local\Programs\Microsoft VS Code
    • Flutter extension version 3.5.1

[√] Connected device (1 available)
    • Android SDK built for x86 • emulator-5556 • android-x86 • Android 8.0.0 (API 26) (emulator)

• No issues found!
felangel commented 5 years ago

Hi @devibrahimkarahan 👋 Thanks for opening an issue!

Are you able to share a link to a sample app with which I can reproduce the issue? Thanks! 👍

devibrahimkarahan commented 5 years ago

Sorry, I'm creating sample app now.

felangel commented 5 years ago

No worries! Thanks 😄

devibrahimkarahan commented 5 years ago

Lol, when i create sample app, i found the solution :). I m using my own localization class, and it have a load function for get strings map from file, and it takes a little bit time, when i remove that line problem resolved. But i dont understand why it works when downgrade to 0.17.0 :)

You can close, sorry. Best regards.

devibrahimkarahan commented 5 years ago

Maybe someone will encounter the same situation I share the solution.

My old load function

Future<void> _load() async {
    String jsonString = await rootBundle.loadString(
      "assets/lang/${_locale.languageCode}.json",
    );
    _strings = Map.from(json.decode(jsonString));
  }

New version

Future<void> _load() async {
    await null;
    rootBundle
        .loadString("assets/lang/${_locale.languageCode}.json")
        .then((jsonString) {
      _strings = Map.from(json.decode(jsonString));
    });
  }
konstantin-doncov commented 4 years ago

@devibrahimkarahan hello. I have the same issue here, please can you check it?