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

如何在Riverpod的Provider中使用对象列表?

Riverpod 实现多页面共享Form状态方案

核心概念快速梳理

  • StateNotifierProvider:封装带更新逻辑的共享状态,把Form列表和修改方法集中管理,所有页面可访问并触发更新。
  • Consumer:局部监听状态变化,仅重建需要更新的UI部分,避免全页面刷新。
  • Selector:精准监听状态中特定字段/对象的变化,适合列表项的局部更新场景。

步骤1:定义Form模型(支持JSON序列化)

先实现Form实体类,支持与JSON互转,满足SharedPreferences存储需求:

import 'dart:convert';

class FormItem {
  final int id;
  String title;
  String content;

  FormItem({
    required this.id,
    required this.title,
    required this.content,
  });

  // 转为JSON格式
  Map<String, dynamic> toJson() {
    return {
      'id': id,
      'title': title,
      'content': content,
    };
  }

  // 从JSON解析为对象
  factory FormItem.fromJson(Map<String, dynamic> json) {
    return FormItem(
      id: json['id'],
      title: json['title'],
      content: json['content'],
    );
  }
}

步骤2:创建StateNotifier管理Form状态

封装本地数据读写、Form更新逻辑,把状态和操作绑定在一起:

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

class FormListNotifier extends StateNotifier<List<FormItem>> {
  FormListNotifier() : super([]) {
    // 初始化时自动加载本地数据
    _loadFromPrefs();
  }

  // 从SharedPreferences读取数据
  Future<void> _loadFromPrefs() async {
    final prefs = await SharedPreferences.getInstance();
    final jsonString = prefs.getString('form_list');
    if (jsonString != null) {
      final List<dynamic> jsonList = jsonDecode(jsonString);
      state = jsonList.map((e) => FormItem.fromJson(e)).toList();
    } else {
      // 无本地数据时使用固定长度的默认列表
      state = [
        FormItem(id: 0, title: '默认表单1', content: '默认内容1'),
        FormItem(id: 1, title: '默认表单2', content: '默认内容2'),
        FormItem(id: 2, title: '默认表单3', content: '默认内容3'),
      ];
      // 把默认值存入本地
      _saveToPrefs();
    }
  }

  // 保存数据到SharedPreferences
  Future<void> _saveToPrefs() async {
    final prefs = await SharedPreferences.getInstance();
    final jsonList = state.map((form) => form.toJson()).toList();
    prefs.setString('form_list', jsonEncode(jsonList));
  }

  // 更新单个Form的方法
  void updateForm(int id, {String? title, String? content}) {
    state = state.map((form) {
      if (form.id == id) {
        return FormItem(
          id: form.id,
          title: title ?? form.title,
          content: content ?? form.content,
        );
      }
      return form;
    }).toList();
    // 更新后自动保存到本地
    _saveToPrefs();
  }
}

// 创建全局Provider,供所有页面调用
final formListProvider = StateNotifierProvider<FormListNotifier, List<FormItem>>(
  (ref) => FormListNotifier(),
);

步骤3:页面1(列表页面,实现局部更新)

用Selector监听单个Form的变化,仅刷新修改的列表项,避免全列表重建:

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

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

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final formList = ref.watch(formListProvider);
    return Scaffold(
      appBar: AppBar(title: const Text('表单列表')),
      body: ListView.builder(
        itemCount: formList.length,
        itemBuilder: (context, index) {
          final targetForm = formList[index];
          // 仅监听当前id的Form变化,变化时只重建该列表项
          return Selector<FormListNotifier, FormItem>(
            selector: (ref, notifier) => notifier.state.firstWhere((f) => f.id == targetForm.id),
            builder: (context, currentForm, child) {
              return ListTile(
                title: Text(currentForm.title),
                subtitle: Text(currentForm.content),
                onTap: () {
                  // 跳转到页面2编辑当前表单
                  Navigator.push(
                    context,
                    MaterialPageRoute(
                      builder: (context) => Page2(formId: currentForm.id),
                    ),
                  );
                },
              );
            },
          );
        },
      ),
    );
  }
}

步骤4:页面2(编辑页面,实现状态同步)

获取指定Form并修改,调用更新方法后,页面1和预览区域会自动同步状态:

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

class Page2 extends ConsumerStatefulWidget {
  final int formId;
  const Page2({super.key, required this.formId});

  @override
  ConsumerState<Page2> createState() => _Page2State();
}

class _Page2State extends ConsumerState<Page2> {
  late TextEditingController _titleController;
  late TextEditingController _contentController;

  @override
  void initState() {
    super.initState();
    // 用当前Form数据初始化输入控制器
    final targetForm = ref.read(formListProvider).firstWhere((f) => f.id == widget.formId);
    _titleController = TextEditingController(text: targetForm.title);
    _contentController = TextEditingController(text: targetForm.content);
  }

  @override
  void dispose() {
    _titleController.dispose();
    _contentController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    return Scaffold(
      appBar: AppBar(title: const Text('编辑表单')),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          children: [
            TextField(
              controller: _titleController,
              decoration: const InputDecoration(labelText: '标题'),
            ),
            TextField(
              controller: _contentController,
              decoration: const InputDecoration(labelText: '内容'),
              maxLines: 3,
            ),
            const SizedBox(height: 20),
            ElevatedButton(
              onPressed: () {
                // 调用Provider的更新方法修改表单
                ref.read(formListProvider.notifier).updateForm(
                      widget.formId,
                      title: _titleController.text,
                      content: _contentController.text,
                    );
                // 返回页面1,此时对应列表项已同步更新
                Navigator.pop(context);
              },
              child: const Text('保存'),
            ),
            const SizedBox(height: 10),
            // 预览按钮,点击后展示最新输入内容
            ElevatedButton(
              onPressed: () {
                showDialog(
                  context: context,
                  builder: (context) {
                    return AlertDialog(
                      title: Text(_titleController.text),
                      content: Text(_contentController.text),
                      actions: [TextButton(onPressed: () => Navigator.pop(context), child: const Text('关闭'))],
                    );
                  },
                );
              },
              child: const Text('预览'),
            ),
          ],
        ),
      ),
    );
  }
}

关键逻辑说明

  1. 本地数据持久化:FormListNotifier初始化时自动读取SharedPreferences数据,更新后自动保存,确保数据不丢失。
  2. 局部更新优化:页面1通过Selector精准监听单个Form的变化,仅重建修改的列表项,不会刷新整个ListView。
  3. 多入口更新支持:任何页面只要获取formListProvider.notifier,调用updateForm即可修改指定Form,所有监听该状态的UI都会同步更新。
  4. 状态实时同步:页面2修改表单后,页面1的对应列表项、预览弹窗会自动更新,无需手动刷新页面。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 04:55:45