felangel / bloc

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

fix: hydrated_bloc #3044

Closed kiaxseventh closed 2 years ago

kiaxseventh commented 2 years ago

Description dear @felangel thanks lot of for everything

hydrated_bloc on initial structure is not good

log :

Storage was accessed before it was initialized.
Please ensure that storage has been initialized.

When we use hydrated_bloc and flutter_native_splash at the same time we see a white screen between splash screen and app

i think first initialization of hydrated_bloc with this structure It is not convenient and flexible

changing first initialization structure to like a singleton pattern primary creation structure is much more effective

This way we can create the code in the background or after runApp() method without force usage on initial app before the main method

felangel commented 2 years ago

Hi @kiaxseventh 👋 Thanks for opening an issue!

Can you please provide a link to a minimal reproduction sample? I highly recommend making sure your setup aligns with how it's done in the hydrated bloc example

kiaxseventh commented 2 years ago

i use [flutter native splash](flutter_native_splash 1.3.2 ) on android and ios version i see a white screen between splash screen and app and it is not good ux ! best solution is HydratedBloc inital move to after runApp(MainApp()) but it is not working

best solution is Hydrated Bloc initial move to after run App(Main App()) but it is not working

this is my example

Future<void> main() async {
  FlavorsConfig.create(Environment.COINBANK,
      name: 'HiEx',
      properties: {
        Keys.app_name: 'HiEx',
        Keys.base_url: 'https://x.x',
        Keys.x_clientid: 'x',
      });

  await Singleton.register(AuthenticationToken.createInstance(
    onRemovedTocken: () async {
      TokenBloc().TokenChecked();
      SecuritySettingsBloc().clearData();
      await HydratedStorage.hive.deleteFromDisk();
    },
    onSavededTocken: () {
      TokenBloc().TokenChecked();
    },
  ));

    WidgetsFlutterBinding.ensureInitialized();

  final storage = await HydratedStorage.build(
    storageDirectory: kIsWeb
        ? HydratedStorage.webStorageDirectory
        : await getTemporaryDirectory(),
  );

  HydratedBlocOverrides.runZoned(
        () => setupMainApp(),
    storage: storage,
  );

  runApp(MainApp());

}
felangel commented 2 years ago

i use [flutter native splash](flutter_native_splash 1.3.2 ) on android and ios version i see a white screen between splash screen and app and it is not good ux ! best solution is HydratedBloc inital move to after runApp(MainApp()) but it is not working

best solution is Hydrated Bloc initial move to after run App(Main App()) but it is not working

this is my example

Future<void> main() async {
  FlavorsConfig.create(Environment.COINBANK,
      name: 'HiEx',
      properties: {
        Keys.app_name: 'HiEx',
        Keys.base_url: 'https://x.x',
        Keys.x_clientid: 'x',
      });

  await Singleton.register(AuthenticationToken.createInstance(
    onRemovedTocken: () async {
      TokenBloc().TokenChecked();
      SecuritySettingsBloc().clearData();
      await HydratedStorage.hive.deleteFromDisk();
    },
    onSavededTocken: () {
      TokenBloc().TokenChecked();
    },
  ));

    WidgetsFlutterBinding.ensureInitialized();

  final storage = await HydratedStorage.build(
    storageDirectory: kIsWeb
        ? HydratedStorage.webStorageDirectory
        : await getTemporaryDirectory(),
  );

  HydratedBlocOverrides.runZoned(
        () => setupMainApp(),
    storage: storage,
  );

  runApp(MainApp());

}

I highly recommend leaving the initialization before runApp and configuring the native splash screen so that you leverage the native splash screen instead of duplicating the effort and having a splash screen in flutter as well.

Hope that helps!

kiaxseventh commented 2 years ago
  final storage = await HydratedStorage.build(
    storageDirectory: kIsWeb
        ? HydratedStorage.webStorageDirectory
        : await getTemporaryDirectory(),
  );

  HydratedBlocOverrides.runZoned(
        () => setupMainApp(),
    storage: storage,
  );

HydratedStorage initialization and HydratedBlocOverrides are just initialization before runApp

I highly recommend leaving the initialization before runApp Of course, I think so too

I do not see the need to initialization of Hydrated before runApp For this reason, I suggest improving the structure

felangel commented 2 years ago
  final storage = await HydratedStorage.build(
    storageDirectory: kIsWeb
        ? HydratedStorage.webStorageDirectory
        : await getTemporaryDirectory(),
  );

  HydratedBlocOverrides.runZoned(
        () => setupMainApp(),
    storage: storage,
  );

HydratedStorage initialization and HydratedBlocOverrides are just initialization before runApp

I highly recommend leaving the initialization before runApp Of course, I think so too

I do not see the need to initialization of Hydrated before runApp For this reason, I suggest improving the structure

The reason is ideally you'd want to show the user the native splash screen while hydrating the storage. Otherwise you'll have to make some sort of loading screen/alternative splash screen later to show the user while the cache is being populated.

kiaxseventh commented 2 years ago

i'm sorry, i know it , but i say other things i say hydrated_bloc with force initial on top of application is not good solution If can you change the initialization structure This problem can be solved

Instead, initialization should be done when the first read or write request is sent to "hydrated_bloc" for example like "BlocProvider" with "lazy true" option this way dont need await for first init application

BlocProvider(
  lazy: true,
  create: (BuildContext context) => BlocA(),
  child: ChildA(),
);
felangel commented 2 years ago

i'm sorry, i know it , but i say other things i say hydrated_bloc with force initial on top of application is not good solution If can you change the initialization structure This problem can be solved

Instead, initialization should be done when the first read or write request is sent to "hydrated_bloc" for example like "BlocProvider" with "lazy true" option this way dont need await for first init application

BlocProvider(
  lazy: true,
  create: (BuildContext context) => BlocA(),
  child: ChildA(),
);

Creation of a bloc is a synchronous operation whereas initializing the storage is asynchronous. If we delay the initialization you'll need to handle awaiting the initialization within the widget tree.

felangel commented 2 years ago

Closing for now but feel free to comment with additional thoughts/comments/feedback and I'm happy to continue the conversation 👍

kiaxseventh commented 2 years ago

thank you lot of Can't really come up with a way to do "HydratedBlocOverrides.runZoned" after "runApp(MaterialApp())"