簡體   English   中英

Flutter RepositoryProvider 和 Hive LateInitializationError

[英]Flutter RepositoryProvider and Hive LateInitializationError

我有一個應用程序,我正在使用 Bloc 和 Hive。

主要.dart

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  final appDocumentDirectory =
      await path_provider.getApplicationDocumentsDirectory();
  Hive.init(appDocumentDirectory.path);

  runApp(
    const MyApp(),
  );
}

在 MyApp 小部件上注冊了 MultiRepositoryProvider

return MultiRepositoryProvider(
  providers: [
    RepositoryProvider(create: (context) => AccountService()),
  ],
  child: MultiBlocProvider(
    providers: [
      BlocProvider<AccountBloc>(
        create: (context) => AccountBloc(context.read<AccountService>()),
      ),
    ],
    child: MaterialApp(
      home: const AppPage(),
    ),
  ),
);

AppPage 包含 bottomNavigationBar 和一些頁面

帳號.dart

class AccountService {
  late Box<Account> _accounts;
  AccountService() {
    init();
  }

  Future<void> init() async {
    Hive.registerAdapter(AccountAdapter());
    _accounts = await Hive.openBox<Account>('accounts');
  }

在 appPage 上有 BlocBuilder

BlocBuilder<AccountBloc, AccountState>(
builder: (context, state) {
  if (state.accountStatus == AccountStatus.loading) {
    return const CircularProgressIndicator();
  } else if (state.accountStatus == AccountStatus.error) {
    Future.delayed(Duration.zero, () {
      errorDialog(context, state.error);
    });
  }
  return SingleChildScrollView(....

首次加載應用程序時,我收到LateInitializationError ,即帳戶存儲庫中的late Box <Account> _accounts未初始化。 但是,一旦我導航到另一個頁面並返回 go, Box <Account> _accounts初始化並顯示數據。 如何避免此錯誤並在應用程序加載時初始化 Hive 框?

你能試試這個嗎? 我認為您需要等待 Hive 初始化函數

 void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  final appDocumentDirectory =
      await path_provider.getApplicationDocumentsDirectory();
  await Hive.init(appDocumentDirectory.path);

  runApp(
    const MyApp(),
  );
}

已經有 7 個月了,但如果您仍在尋找答案,不確定它是否是最佳答案,但下面的答案應該可行。

我對您遇到的問題的理解是,出現“LateInitializationError”的原因是因為您的構造函數中的 init function 調用是異步調用的,無需等待其結果。 當您導航到另一個頁面並返回 go 時,function init 運行恰好完成。 因此,錯誤消失了。 這里的復雜性在於構造函數不能標記為異步,以便您使用該 await 關鍵字。 由於您使用的是 bloc,一種可能的解決方法是當 bloc 在 init state 中時調用 repo 的 init function。

出於演示目的,我在下面定義了 bloc 狀態和事件,您完全可以根據需要更改它們。

// bloc states
abstract class AccountState{}

class InitState extends AccountState{}

class LoadedState extends AccountState{
LoadedState(this.accounts);
final List<Account> accounts;
}

class LoadingErrorState  extends AccountState{}

//bloc events
abstract class AccountEvent {}

class InitEvent extends AccountEvent {}
... // other events

在您的集團邏輯中,您可以在 InitEvent 上從您的 repo 調用 init function

class AccountBloc extends Bloc<AccountEvent, AccountState> {
  AccountBloc(this.repo) : super(InitState()) {
    on<InitEvent>((event, emit) async {
      await repo.init();
      emit(LoadedState(account: repo.getAccounts()));
    });
    ...// define handlers for other events
  }
  final AccountRepository repo;
}

在您的服務 class 中,您可以從構造函數中刪除 init,例如:

class AccountService {
  late Box<Account> _accounts;
  AccountService();

  Future<void> init() async {
    Hive.registerAdapter(AccountAdapter());
    _accounts = await Hive.openBox<Account>('accounts');
  }
 
  List<Account> getAccounts(){
    return _accounts.values.toList();
  }
}

然后在你的 bloc 構建器中,當 state 為 InitState 時,你可以將 init 事件添加到你的 bloc,如下所示:

BlocBuilder<AccountBloc, AccountState>(
builder: (context, state) {
  if (state is InitState) {
    context.read<AccountBloc>.add(InitEvent());
    return const CircularProgressIndicator();
  } else if (state is LoadingErrorState) {
    Future.delayed(Duration.zero, () {
      errorDialog(context, state.error);
    });
  }
  else if (state is LoadedState){
  return SingleChildScrollView(....
  }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM