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

Flutter GetX框架对接NewsAPI时模型类型转换报错如何解决

问题解决方法

核心错误1:JSON解析结构和接口返回不匹配

NewsAPI的接口返回最外层是单个JSON对象(包含status、totalResults、articles三个字段),而非JSON数组,你当前的解析逻辑错误将外层结构当做数组处理,是触发类型转换错误的核心原因。

核心错误2:空安全类型声明不匹配

接口返回的author、urlToImage、source.id等字段可能为null,但你在模型中声明为非空的String类型且加了required修饰,空值赋值给非空变量会直接抛出类型异常。


具体修改步骤

1. 修正JSON序列化模型

修改newsFromJson方法的返回值,同时修正所有可空字段的类型声明,示例代码如下:

// To parse this JSON data, do
//
//     final newsResponse = newsFromJson(jsonString);

import 'package:meta/meta.dart';
import 'dart:convert';

// 修正:返回单个News对象,不是数组
News newsFromJson(String str) => News.fromJson(json.decode(str));

String newsToJson(News data) => json.encode(data.toJson());

class News {
  News({
    required this.status,
    required this.totalResults,
    required this.articles,
  });

  final String status;
  final int totalResults;
  final List<Article> articles;

  factory News.fromJson(Map<String, dynamic> json) => News(
        status: json["status"],
        totalResults: json["totalResults"],
        articles: List<Article>.from(json["articles"].map((x) => Article.fromJson(x))),
      );

  Map<String, dynamic> toJson() => {
        "status": status,
        "totalResults": totalResults,
        "articles": List<dynamic>.from(articles.map((x) => x.toJson())),
      };
}

class Article {
  Article({
    required this.source,
    this.author, // 去掉required,改为可空类型
    required this.title,
    this.description, // 可空
    required this.url,
    this.urlToImage, // 可空
    required this.publishedAt,
    this.content, // 可空
  });

  final Source source;
  final String? author; // 类型改为String?
  final String title;
  final String? description;
  final String url;
  final String? urlToImage;
  final DateTime publishedAt;
  final String? content;

  factory Article.fromJson(Map<String, dynamic> json) => Article(
        source: Source.fromJson(json["source"]),
        author: json["author"],
        title: json["title"],
        description: json["description"],
        url: json["url"],
        urlToImage: json["urlToImage"],
        publishedAt: DateTime.parse(json["publishedAt"]),
        content: json["content"],
      );

  Map<String, dynamic> toJson() => {
        "source": source.toJson(),
        "author": author,
        "title": title,
        "description": description,
        "url": url,
        "urlToImage": urlToImage,
        "publishedAt": publishedAt.toIso8601String(),
        "content": content,
      };
}

class Source {
  Source({
    this.id, // 可空,去掉required
    required this.name,
  });

  final String? id; // 类型改为String?
  final String name;

  factory Source.fromJson(Map<String, dynamic> json) => Source(
        id: json["id"],
        name: json["name"],
      );

  Map<String, dynamic> toJson() => {
        "id": id,
        "name": name,
      };
}

2. 修正远程请求类remoteservice.dart

修改返回值类型为单个News对象:

import 'package:http/http.dart' as http;
import 'package:nocovid/models/news.dart';
import 'package:nocovid/utils/constant.dart';

class RemoteServices {
  static var client = http.Client();

  // 修正返回值为News?
  static Future<News?> fetchNews() async {
    final String endpoint =
        'https://newsapi.org/v2/everything?q=covid19&apiKey=' + kAPIKey;
    final Uri url = Uri.parse(endpoint);

    final response = await client.get(url);
    if (response.statusCode == 200) {
      var jsonString = response.body;
      return newsFromJson(jsonString);
    } else {
      return null;
    }
  }
}

3. 修正GetX控制器newscontroller.dart

存储实际需要渲染的文章列表,而非整个响应对象:

import 'package:get/state_manager.dart';
import 'package:nocovid/models/news.dart';
import 'package:nocovid/services/remote_services.dart';

class NewsController extends GetxController {
  // 修正:存储文章列表Article,不是News
  var articleList = <Article>[].obs;

  @override
  void onInit() {
    fetchNews();
    super.onInit();
  }

  void fetchNews() async {
    var newsResponse = await RemoteServices.fetchNews();
    if (newsResponse != null) {
      articleList.value = newsResponse.articles;
    }
  }
}

额外排查技巧

如果修改后仍有问题,可以先打印接口返回的原始JSON字符串,对比字段名、字段类型和模型声明是否完全一致,尤其是大小写、数字/字符串类型混淆的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 10:39:02