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

Flutter列表模型类数据调用问题:Provider取值为空求助

解决Provider获取模型数据为null的问题

核心问题分析

  1. Widget未监听Provider变化:使用listen: false时,Widget不会响应notifyListeners()的更新,初始categories为null,后续数据加载完成也不会重建Widget展示新数据。
  2. 模型类不必要继承ChangeNotifier:Categories和Data作为数据模型,不需要继承ChangeNotifier,只有负责状态管理的Category类需要。
  3. 可能未触发API调用:如果没有在合适的时机调用getCatogories方法,categories始终为null。
  4. 空安全处理不严谨:代码中使用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 12:30:51