Flutter使用provider包监听状态变化实现Widget自动重建的方法咨询
实现方案
你遇到的核心问题是local storage本身没有内置的变化监听能力,需要把业务数据存在Provider的可监听状态层,同时和local storage做双向同步即可,具体实现步骤如下:
1. 定义可监听的状态管理类
继承ChangeNotifier封装订阅数据的读写逻辑,所有对数据的修改都走这个类的方法,保证修改后可以通知UI更新。
import 'package:flutter/foundation.dart'; import 'package:shared_preferences/shared_preferences.dart'; // 可以替换成你自己的业务数据实体类,这里用通用结构做示例 typedef SubscriptionItem = Map<String, dynamic>; class SubscribeDataNotifier extends ChangeNotifier { List<SubscriptionItem> _dataList = []; List<SubscriptionItem> get dataList => _dataList; // 初始化时从local storage拉取历史数据 Future<void> init() async { final prefs = await SharedPreferences.getInstance(); final cacheStr = prefs.getString('graphql_subscribe_cache'); if (cacheStr != null) { // 此处替换为你自己的反序列化逻辑,把字符串转成业务数据结构 // _dataList = 反序列化结果; notifyListeners(); } } // 收到GraphQL推送新数据时调用该方法 Future<void> addNewData(SubscriptionItem newItem) async { // 更新内存中的状态 _dataList.add(newItem); // 同步写入local storage持久化 final prefs = await SharedPreferences.getInstance(); // 此处替换为你自己的序列化逻辑,把业务数据转成字符串存储 // final cacheStr = 序列化结果; await prefs.setString('graphql_subscribe_cache', cacheStr); // 通知所有监听的Widget重建 notifyListeners(); } }
2. 顶层注册Provider
在App入口把状态类注册到Widget树,全局可访问:
void main() { runApp( ChangeNotifierProvider( create: (context) => SubscribeDataNotifier()..init(), child: const MyApp(), ), ); }
3. GraphQL订阅回调中触发数据更新
在你的订阅逻辑里,收到后端推送的数据后,调用状态类的更新方法即可:
// 你的GraphQL订阅初始化逻辑 void initSubscribe(BuildContext context) { final client = GraphQLClient(/* 你的客户端配置 */); client.subscribe(SubscriptionOptions( document: gql('你的订阅查询语句'), )).listen((result) { if (result.hasException || result.data == null) return; final newItem = result.data!['订阅返回的字段名']; // 调用状态类更新方法 context.read<SubscribeDataNotifier>().addNewData(newItem); }); }
4. UI层监听数据自动更新
需要展示数据的Widget中,用watch或者Consumer监听状态变化即可自动重建:
class DataListWidget extends StatelessWidget { const DataListWidget({super.key}); @override Widget build(BuildContext context) { // 监听数据变化,数据更新时自动触发build final dataList = context.watch<SubscribeDataNotifier>().dataList; return ListView.builder( itemCount: dataList.length, itemBuilder: (context, index) { return ListTile( title: Text(dataList[index]['你要展示的字段名']), ); }, ); } }
注意:所有对这份订阅数据的读写都要走
SubscribeDataNotifier的封装方法,不要在业务代码中直接操作SharedPreferences实例,否则会出现数据和UI不同步的问题。
内容的提问来源于stack exchange,提问作者EA vijay
相关产品推荐
相关产品推荐

