You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Riverpod初始化Isar?现有初始化偶发失败求排查优化

Isar初始化偶尔失败的问题排查与优化方案

核心问题分析

1. 未向外传递初始化异常

你的initIsar方法捕获了异常但未抛出,导致FutureProvider会错误地认为初始化已成功,返回的IsarService实例中isar变量(late修饰)可能未被赋值,后续调用时就会触发LateInitializationError,也就是你看到的“Isar not initialized.”错误。

2. 单例与FutureProvider的潜在冲突

虽然IsarService是单例,但FutureProvider每次被重新订阅时,都会再次调用initIsar方法。如果第一次初始化失败,后续重复调用可能导致不可预期的状态;如果初始化成功后再次调用Isar.open,也可能引发数据库连接冲突。

3. 启动初始化的时机与错误处理缺失

用Future.delayed(Duration.zero)在initState中触发初始化,时机不可靠,且初始化失败后没有重试或降级逻辑,进而出现无报错但无法拉取数据的情况。

优化后的代码实现

1. 修复IsarService类

class IsarService {
  Isar? _isar;
  static final IsarService _instance = IsarService._internal();

  IsarService._internal();
  factory IsarService() => _instance;

  final schemaList = [
    SearchedUserLocationSchema,
    SavedLocationModelSchema,
    SelectedUserLocationSchema
  ];

  bool get isInitialized => _isar != null && _isar!.isOpen;

  Future<void> initIsar() async {
    if (isInitialized) return; // 避免重复初始化

    try {
      _isar = await Isar.open(
        maxSizeMiB: Isar.defaultMaxSizeMiB,
        directory: (await getApplicationSupportDirectory()).path,
        schemas: schemaList.cast<CollectionSchema>(),
        inspector: true,
      );
      kLog('Isar DB Initialized');
    } catch (e, s) {
      kLog('Isar初始化失败: $e');
      kLog(s);
      rethrow; // 抛出异常,让上层感知初始化失败
    }
  }

  // 提供安全的Isar实例访问方式
  Isar get isar {
    if (!isInitialized) {
      throw StateError('Isar not initialized.');
    }
    return _isar!;
  }
}

2. 优化Riverpod Provider

改用AsyncNotifierProvider更好地管理初始化状态,支持重试:

import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'isar_service.dart';

class IsarNotifier extends AsyncNotifier<IsarService> {
  @override
  Future<IsarService> build() async {
    final service = IsarService();
    await service.initIsar();
    return service;
  }

  // 提供重试初始化的方法
  Future<void> retryInit() async {
    state = const AsyncLoading();
    try {
      final service = IsarService();
      await service.initIsar();
      state = AsyncData(service);
    } catch (e, s) {
      kLog('重试初始化失败: $e');
      kLog(s);
      state = AsyncError(e, s);
    }
  }
}

final isarServiceProvider = AsyncNotifierProvider<IsarNotifier, IsarService>(
  () => IsarNotifier(),
);

3. 优化应用启动初始化逻辑

@override
void initState() {
  super.initState();
  _initIsar();
}

Future<void> _initIsar() async {
  final asyncValue = ref.watch(isarServiceProvider);
  asyncValue.when(
    data: (_) => kLog('Isar初始化完成'),
    loading: () => kLog('Isar初始化中'),
    error: (e, s) {
      kLog('Isar初始化失败,准备重试');
      // 延迟1秒重试,可根据需求调整次数
      Future.delayed(const Duration(seconds: 1), () {
        ref.read(isarServiceProvider.notifier).retryInit();
      });
    },
  );
}

额外建议

  • 权限检查: Android需确认AndroidManifest.xml中是否添加存储权限(针对旧版本系统);iOS需确保Info.plist配置了沙箱权限。
  • 状态前置判断: 业务代码中访问isar前,先通过isInitialized判断状态,避免崩溃。
  • 日志增强: 数据拉取失败时,输出IsarService().isInitialized的状态,快速定位问题。

内容的提问来源于stack exchange,提问作者Abdul Kader Hridoy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 16:40:19