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

如何在SharedPreferences变更时重建StreamBuilder组件

解决方案

你之前用FutureBuilder包裹的问题在于,它只会在首次获取startDate时构建一次,当用户修改设置后,Future不会重新执行,所以StreamBuilder不会感知到设置变化,自然不会重建列表。要实现设置修改后触发StreamBuilder重建,需要把SharedPreferences的变化转换成可监听的Stream,再和数据库的数据流结合。

方法一:用Stream管理设置变化(推荐)

1. 创建设置管理类

这个类负责封装SharedPreferences的读写,并将设置变化以Stream的形式对外发布:

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

class SettingsManager {
  static final SettingsManager _instance = SettingsManager._internal();
  factory SettingsManager() => _instance;
  SettingsManager._internal();

  final _startDateController = StreamController<int>.broadcast();
  int? _currentStartDate;

  Stream<int> get startDateStream => _startDateController.stream;

  Future<void> init() async {
    final prefs = await SharedPreferences.getInstance();
    _currentStartDate = prefs.getInt('startDate') ?? 0;
    _startDateController.add(_currentStartDate!);
  }

  Future<void> updateStartDate(int newDate) async {
    final prefs = await SharedPreferences.getInstance();
    await prefs.setInt('startDate', newDate);
    _currentStartDate = newDate;
    _startDateController.add(newDate);
  }

  void dispose() {
    _startDateController.close();
  }
}

2. 修改Overview组件为StatefulWidget

合并设置流和数据库流,让任意一个变化都触发UI重建:

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

// 替换成你的数据模型
class YourDataModel {
  final int date;
  // 其他字段...
  YourDataModel(this.date);
}

class Overview extends StatefulWidget {
  const Overview({super.key});

  @override
  State<Overview> createState() => _OverviewState();
}

class _OverviewState extends State<Overview> {
  late final SettingsManager _settingsManager;
  late final Stream<List<YourDataModel>> _combinedStream;

  @override
  void initState() {
    super.initState();
    _settingsManager = SettingsManager();
    _settingsManager.init();

    // 合并设置流与数据库流,任意一个更新都会触发builder
    _combinedStream = CombineLatestStream.combine2(
      _settingsManager.startDateStream,
      database.watchAll(), // 你的数据库数据流
      (int startDate, List<YourDataModel> data) {
        // 这里可根据startDate过滤数据,不需要过滤直接返回data即可
        return data.where((item) => item.date >= startDate).toList();
      },
    );
  }

  @override
  void dispose() {
    _settingsManager.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      height: 230,
      margin: const EdgeInsets.all(10),
      padding: const EdgeInsets.all(20),
      decoration: BoxDecoration(
        borderRadius: BorderRadius.circular(10),
        gradient: LinearGradient(
          begin: Alignment.topCenter,
          end: Alignment.bottomCenter,
          colors: [
            Theme.of(context).colorScheme.primaryContainer,
            Theme.of(context).colorScheme.inversePrimary,
          ],
        ),
        boxShadow: [
          BoxShadow(
            color: Colors.black.withOpacity(0.1),
            spreadRadius: 2,
            blurRadius: 8,
            offset: const Offset(0, 2),
          )
        ],
      ),
      child: StreamBuilder<List<YourDataModel>>(
        stream: _combinedStream,
        builder: (context, snapshot) {
          if (snapshot.connectionState == ConnectionState.waiting) {
            return const Center(child: CircularProgressIndicator());
          }
          if (snapshot.hasError) {
            return const Center(child: Text('加载出错'));
          }
          final data = snapshot.data ?? [];
          return ListView.builder(
            itemCount: data.length,
            itemBuilder: (context, index) {
              // 替换成你的列表项UI
              return ListTile(title: Text('数据项 ${data[index].date}'));
            },
          );
        },
      ),
    );
  }
}

3. 修改设置时触发更新

当用户修改startDate时,调用以下代码即可触发StreamBuilder重建:

await SettingsManager().updateStartDate(newValue);

方法二:手动监听状态(无需第三方包)

如果不想引入rxdart,可以在State中分别监听设置和数据库的变化,通过setState触发重建:

class _OverviewState extends State<Overview> {
  late final SettingsManager _settingsManager;
  int _startDate = 0;
  List<YourDataModel> _data = [];

  @override
  void initState() {
    super.initState();
    _settingsManager = SettingsManager();
    _initSettings();
    _listenToDatabase();
  }

  Future<void> _initSettings() async {
    await _settingsManager.init();
    _settingsManager.startDateStream.listen((newDate) {
      setState(() => _startDate = newDate);
    });
  }

  void _listenToDatabase() {
    database.watchAll().listen((newData) {
      setState(() => _data = newData);
    });
  }

  @override
  void dispose() {
    _settingsManager.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    // 根据startDate过滤数据
    final filteredData = _data.where((item) => item.date >= _startDate).toList();

    return Container(
      // 装饰部分不变
      child: ListView.builder(
        itemCount: filteredData.length,
        itemBuilder: (context, index) {
          return ListTile(title: Text('数据项 ${filteredData[index].date}'));
        },
      ),
    );
  }
}

内容的提问来源于stack exchange,提问作者ls.moose

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 16:10:36