Flutter列表模型类数据调用问题:Provider取值为空求助
解决Provider获取模型数据为null的问题
核心问题分析
- Widget未监听Provider变化:使用
listen: false时,Widget不会响应notifyListeners()的更新,初始categories为null,后续数据加载完成也不会重建Widget展示新数据。 - 模型类不必要继承ChangeNotifier:
Categories和Data作为数据模型,不需要继承ChangeNotifier,只有负责状态管理的Category类需要。 - 可能未触发API调用:如果没有在合适的时机调用
getCatogories方法,categories始终为null。 - 空安全处理不严谨:代码中使用
data!强制解包,容易引发空指针异常。
解决方案步骤
1. 修正模型类(移除不必要的ChangeNotifier)
修改Categories和Data类,仅保留数据模型功能:
import 'package:flutter/material.dart'; class Categories { Categories({this.statusCode, this.success, this.messages, this.data}); final int? statusCode; final bool? success; final List<dynamic>? messages; final List<Data>? data; Categories.fromJson(Map<String, dynamic> json) : statusCode = json['statusCode'], success = json['success'], messages = List.castFrom<dynamic, dynamic>(json['messages']), data = List.from(json['data']).map((e) => Data.fromJson(e)).toList(); Map<String, dynamic> toJson() { final _data = <String, dynamic>{}; _data['statusCode'] = statusCode; _data['success'] = success; _data['messages'] = messages; _data['data'] = data?.map((e) => e.toJson()).toList(); return _data; } List<Data> get items { return [...?data]; // 空安全的展开方式 } } class Data { Data({this.id, this.title, this.filename, this.mimetype, this.directcalling, this.parentid, this.subcat}); final int? id; final String? title; final String? filename; final String? mimetype; final int? directcalling; final dynamic parentid; // 用dynamic代替Null,适配更多场景 final List<Subcat>? subcat; Data.fromJson(Map<String, dynamic> json) : id = json['id'], title = json['title'], filename = json['filename'], mimetype = json['mimetype'], directcalling = json['directcalling'], parentid = json['parentid'], subcat = List.from(json['subcat']).map((e) => Subcat.fromJson(e)).toList(); Map<String, dynamic> toJson() { final _data = <String, dynamic>{}; _data['title'] = title; _data['filename'] = filename; _data['directcalling'] = directcalling; return _data; } } class Subcat { Subcat({required this.id, required this.title, required this.filename, required this.mimetype, required this.directcalling, required this.parentid, required this.subcat}); final int id; final String title; final String filename; final String mimetype; final int directcalling; final int parentid; final List<dynamic> subcat; Subcat.fromJson(Map<String, dynamic> json) : id = json['id'], title = json['title'], filename = json['filename'], mimetype = json['mimetype'], directcalling = json['directcalling'], parentid = json['parentid'], subcat = List.castFrom<dynamic, dynamic>(json['subcat']); Map<String, dynamic> toJson() { final _data = <String, dynamic>{}; _data['title'] = title; _data['filename'] = filename; _data['directcalling'] = directcalling; return _data; } }
2. 修正Widget代码(监听Provider变化)
将listen: false改为默认的listen: true,让Widget响应数据更新,同时优化空安全判断:
// 建议改为StatefulWidget,方便在initState中触发API调用 class YourWidget extends StatefulWidget { const YourWidget({super.key}); @override State<YourWidget> createState() => _YourWidgetState(); } class _YourWidgetState extends State<YourWidget> { @override void initState() { super.initState(); // 初始化时调用API获取数据 Provider.of<Category>(context, listen: false).getCatogories(context); } @override Widget build(BuildContext context) { var image = Provider.of<FlutterFunctions>(context, listen: false); var categoryProvider = Provider.of<Category>(context); var cat = categoryProvider.categories; return Scaffold( appBar: AppBar(), drawer: const AppDrawer(), body: Text( cat == null ? "加载中..." : cat.statusCode == null ? "数据异常" : "状态码:${cat.statusCode}" ), ); } }
3. 优化API转换代码(空安全处理)
在Category类中避免强制解包,确保逻辑严谨:
class Category with ChangeNotifier { Categories? categories; Future<void> getCatogories(BuildContext cont) async { final url = PurohitApi().baseUrl + PurohitApi().getcategory; try { final client = RetryClient( http.Client(), retries: 4, when: (response) => response.statusCode == 401, onRetry: (req, res, retryCount) async { if (retryCount == 0 && res?.statusCode == 401) { var accessToken = await Provider.of<Auth>(cont, listen: false).restoreAccessToken(); req.headers['Authorization'] = accessToken; } }, ); var response = await client.get( Uri.parse(url), headers: {'Content-Type': 'application/json; charset=UTF-8'}, ); Map<String, dynamic> categoryTypes = json.decode(response.body); categories = Categories.fromJson(categoryTypes); notifyListeners(); // 通知所有监听的Widget更新数据 } catch (e) { print(e); } } }
内容的提问来源于stack exchange,提问作者Santosh Kumar
相关产品推荐
相关产品推荐

