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

Synchronous fromJson and toJson causing jank issue while dealing with large state #2639

Open yun-cheng opened 3 years ago

yun-cheng commented 3 years ago

Hi! I'm using hydrated_bloc to continuously saving large and deep state but causing jank issue.

So I want to use separate isolate to avoid jank following this tutorial. https://flutter.dev/docs/cookbook/networking/background-parsing

But right now it is not possible using separate isolate in to/from json because they are synchronous. And I noticed that there was an issue #1420 saying

to/from json must be synchronous based on the current API specification

Just wondering if it is still that case.

I know I can solve with adding an event to pre-convert json with separate isolate and return specific Map state.

felangel commented 3 years ago

Hi @yun-cheng 👋 Thanks for opening an issue!

Yes currently this is a limitation and we're working on defining how isolates can be more easily supported when using hydrated_bloc (related to #2633). It would be really helpful if you could provide a minimal reproduction sample of the use-case you have to make sure we take into consideration your usage.

Thanks! 🙏

lhmzhou commented 3 years ago

"jank issue" 😆 💯

jopmiddelkamp commented 1 year ago

Maybe as a temporary solution you can just manually allow what is being stored. I do the same at this moment. I just store the bare minimum that is required.

I know it is not ideal but it works and gives you more control to combat the janks.

  @override
  Map<String, dynamic> toJson(AccountDataState state) {
    final result = {
      'defaultCurrency': state.defaultCurrency?.toJson(),
      'spendableBalances': state.spendableBalances
          ?.map((key, value) => MapEntry(key, value.toJson())),
      'savingsBalances': state.savingsBalances
          ?.map((key, value) => MapEntry(key, value.toJson())),
    };
    return result;
  }

  @override
 AccountDataState fromJson(Map<String, dynamic> json) {
    final result = AccountDataState(
      defaultCurrency: json['defaultCurrency'] != null
          ? CurrencyEntity.fromJson(json['defaultCurrency'])
          : null,
      spendableBalances: json['spendableBalances'] is Map<String, dynamic>
          ? (json['spendableBalances'] as Map<String, dynamic>).map(
              (key, value) => MapEntry(
                key,
                ConvertedBalance.fromJson(value),
              ),
            )
          : null,
      savingsBalances: json['savingsBalances'] is Map<String, dynamic>
          ? (json['savingsBalances'] as Map<String, dynamic>).map(
              (key, value) => MapEntry(
                key,
                ConvertedBalance.fromJson(value),
              ),
            )
          : null,
    );
    return result;
  }

This way you can also if you load many transactions but only serialise a couple of them. So lets say you load 100+ transactions into your bloc state you can say you only serialise the first 10.