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

Flutter调用TMDB API遇类型错误:String无法转为Map<dynamic, dynamic>

解决TMDB API请求中的类型转换错误

错误根源

你遇到的两个错误都是JSON解析时的类型不匹配导致的,和TMDB返回的结构(外层是包含results数组的对象)不对应:

  • 第一个错误:尝试将某个字符串值当作Map<dynamic,dynamic>处理,比如未正确解析整个响应就直接访问内部字段
  • 第二个错误:改成var后,误将字符串当作数组索引使用(数组只能用整数索引)

分步解决

1. 定义匹配TMDB结构的实体类

创建与返回JSON严格对应的实体类,避免类型不匹配:

Movie实体类(对应单条电影数据)

class Movie {
  final bool adult;
  final String? backdropPath;
  final List<int> genreIds;
  final int id;
  final String originalLanguage;
  final String originalTitle;
  final String overview;
  final double popularity;
  final String? posterPath;
  final String releaseDate;
  final String title;
  final bool video;
  final double voteAverage;
  final int voteCount;

  Movie({
    required this.adult,
    this.backdropPath,
    required this.genreIds,
    required this.id,
    required this.originalLanguage,
    required this.originalTitle,
    required this.overview,
    required this.popularity,
    this.posterPath,
    required this.releaseDate,
    required this.title,
    required this.video,
    required this.voteAverage,
    required this.voteCount,
  });

  factory Movie.fromJson(Map<String, dynamic> json) {
    return Movie(
      adult: json['adult'] as bool,
      backdropPath: json['backdrop_path'] as String?,
      genreIds: (json['genre_ids'] as List).map((e) => e as int).toList(),
      id: json['id'] as int,
      originalLanguage: json['original_language'] as String,
      originalTitle: json['original_title'] as String,
      overview: json['overview'] as String,
      popularity: json['popularity'] as double,
      posterPath: json['poster_path'] as String?,
      releaseDate: json['release_date'] as String,
      title: json['title'] as String,
      video: json['video'] as bool,
      voteAverage: (json['vote_average'] as num).toDouble(),
      voteCount: json['vote_count'] as int,
    );
  }
}

外层响应实体类(对应TMDB返回的完整结构)

class MovieResponse {
  final int page;
  final List<Movie> results;
  final int totalPages;
  final int totalResults;

  MovieResponse({
    required this.page,
    required this.results,
    required this.totalPages,
    required this.totalResults,
  });

  factory MovieResponse.fromJson(Map<String, dynamic> json) {
    var resultsList = json['results'] as List;
    List<Movie> movies = resultsList.map((i) => Movie.fromJson(i as Map<String, dynamic>)).toList();

    return MovieResponse(
      page: json['page'] as int,
      results: movies,
      totalPages: json['total_pages'] as int,
      totalResults: json['total_results'] as int,
    );
  }
}

2. 修正ApiService的解析逻辑

确保先将响应体解析为Map,再转换为实体类,避免直接操作字符串:

import 'dart:convert';
import 'package:http/http.dart' as http;

class ApiService {
  final String baseUrl = 'https://api.themoviedb.org/3';
  final String apiKey = '你的API_KEY'; // 替换为你的TMDB API Key

  Future<MovieResponse> getPopularMovies() async {
    final response = await http.get(
      Uri.parse('$baseUrl/movie/popular?api_key=$apiKey'),
    );

    if (response.statusCode == 200) {
      // 必须先解析响应体为Map
      Map<String, dynamic> jsonData = jsonDecode(response.body);
      return MovieResponse.fromJson(jsonData);
    } else {
      throw Exception('加载电影数据失败');
    }
  }
}

3. 排查常见错误点

  • 禁止直接将response.body当作Map使用,必须通过jsonDecode()解析
  • 遍历results时,要操作数组元素(用整数索引或forEach),不要用字符串键访问(比如不要写results['title'],应该是results[0].title)
  • 字段类型严格匹配:比如vote_average是num类型,需转为double;backdrop_path可能为null,设为String?
  • 检查API请求URL是否正确,确保包含api_key参数,避免返回错误提示的JSON字符串

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 20:41:08