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

基于Riverpod实现带Secure Storage的AppState类及Provider的疑问

解决Riverpod代码生成式范式下的App状态持久化问题

核心思路

你需要用@riverpod注解生成AsyncNotifierProvider(而非简单的StateProvider),结合flutter_secure_storage实现状态的持久化与UI同步。这种方式既保留了自动生成Provider的便利性,又能处理异步加载/保存逻辑。

步骤1:依赖配置

确保pubspec.yaml中包含以下依赖:

dependencies:
  flutter:
    sdk: flutter
  riverpod_annotation: ^2.3.0
  flutter_secure_storage: ^9.0.0
  json_annotation: ^4.8.1

dev_dependencies:
  build_runner: ^2.4.4
  riverpod_generator: ^2.3.0
  json_serializable: ^6.7.0

步骤2:定义App配置模型

创建包含配置项的实体类,实现序列化/反序列化方法:

import 'package:json_annotation/json_annotation.dart';

part 'app_settings.g.dart';

@JsonSerializable()
class AppSettings {
  final bool darkMode;

  AppSettings({required this.darkMode});

  // 序列化方法
  Map<String, dynamic> toJson() => _$AppSettingsToJson(this);

  // 反序列化方法,带默认值
  factory AppSettings.fromJson(Map<String, dynamic> json) =>
      _$AppSettingsFromJson(json);

  // 复制方法,用于更新状态
  AppSettings copyWith({bool? darkMode}) {
    return AppSettings(
      darkMode: darkMode ?? this.darkMode,
    );
  }
}

步骤3:生成带持久化的Notifier Provider

用@riverpod注解创建Notifier,负责加载初始配置、更新状态、持久化数据:

import 'dart:convert';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'app_settings.dart';

part 'app_settings_provider.g.dart';

@riverpod
class AppSettingsNotifier extends _$AppSettingsNotifier {
  final _storage = const FlutterSecureStorage();
  static const _storageKey = 'app_settings';

  // 初始化:从Secure Storage加载配置
  @override
  FutureOr<AppSettings> build() async {
    final savedSettings = await _storage.read(key: _storageKey);
    if (savedSettings != null) {
      return AppSettings.fromJson(jsonDecode(savedSettings));
    }
    // 无保存数据时返回默认配置
    return AppSettings(darkMode: false);
  }

  // 更新深色模式并持久化
  Future<void> updateDarkMode(bool newValue) async {
    // 先同步更新状态,触发UI重绘
    state = AsyncData(state.value!.copyWith(darkMode: newValue));
    // 异步保存到Secure Storage
    await _storage.write(
      key: _storageKey,
      value: jsonEncode(state.value!.toJson()),
    );
  }
}

步骤4:在UI中使用Provider

在设置页通过ref.watch监听状态,通过ref.read调用更新方法:

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'app_settings_provider.dart';

class SettingsPage extends ConsumerWidget {
  const SettingsPage({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final settingsAsync = ref.watch(appSettingsNotifierProvider);

    return Scaffold(
      appBar: AppBar(title: const Text('设置')),
      body: settingsAsync.when(
        loading: () => const Center(child: CircularProgressIndicator()),
        error: (err, stack) => Center(child: Text('加载失败: $err')),
        data: (settings) {
          return ListTile(
            title: const Text('深色模式'),
            trailing: Switch(
              value: settings.darkMode,
              onChanged: (value) {
                ref.read(appSettingsNotifierProvider.notifier).updateDarkMode(value);
              },
            ),
          );
        },
      ),
    );
  }
}

关键说明

  1. 代码生成:执行flutter pub run build_runner build生成.g.dart后缀的自动代码文件。
  2. AsyncValue处理:因为初始加载是异步操作,状态以AsyncValue形式存在,必须用when方法处理加载、错误、成功三种状态。
  3. 扩展配置:如果需要添加更多设置项,只需在AppSettings类中新增字段,补充序列化方法,再在Notifier中添加对应的更新函数即可。

内容的提问来源于stack exchange,提问作者Noh Kumado

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 09:18:29