Home > Mobile >  Exception: type 'String' is not a subtype of type 'Map<dynamic, dynamic>'
Exception: type 'String' is not a subtype of type 'Map<dynamic, dynamic>'

Time:10-31

I'm trying to get some images from an API but facing this error

[ERROR:flutter/lib/ui/ui_dart_state.cc(198)] Unhandled Exception: type 'String' is not a subtype of type 'Map<dynamic, dynamic>'

The Json from the API looks like this and it's from www.themoviedb.org:

{
  "page": 1,
  "results": [
    {
      "adult": false,
      "backdrop_path": "/qxeqKcVBWnQxUp1w6fwWcxZEA6m.jpg",
      "genre_ids": [
        28,
        12,
        14
      ],
      "id": 436270,
      "original_language": "en",
      "original_title": "Black Adam",
      "overview": "Nearly 5,000 years after he was bestowed with the almighty powers of the Egyptian gods—and imprisoned just as quickly—Black Adam is freed from his earthly tomb, ready to unleash his unique form of justice on the modern world.",
      "popularity": 6041.545,
      "poster_path": "/3zXceNTtyj5FLjwQXuPvLYK5YYL.jpg",
      "release_date": "2022-10-19",
      "title": "Black Adam",
      "video": false,
      "vote_average": 7.2,
      "vote_count": 425
    },  
   ],
  "total_pages": 35601,
  "total_results": 712013
}

Here is the code:

Movie

class Movie {
  final int id;
  final String name;
  final String description;
  final String? posterPath;

//<editor-fold desc="Data Methods">

  Movie({
    required this.id,
    required this.name,
    required this.description,
    this.posterPath,
  });

  Movie copyWith({
    int? id,
    String? name,
    String? description,
    String? posterPath,
  }) {
    return Movie(
      id: id ?? this.id,
      name: name ?? this.name,
      description: description ?? this.description,
      posterPath: posterPath ?? this.posterPath,
    );
  }

  factory Movie.fromJson(Map<String, dynamic> map) {
    return Movie(
      id: map['id'] as int,
      name: map['title'] as String,
      description: map['overview'] as String,
      posterPath: map['poster_path'] as String,
    );
  }

  // Poster url ****************************************************************

  String posterUrl() {
    Api api = Api();

    return api.baseUrl   posterPath!;
  }

//</editor-fold>
}

API

class Api {
  final String apiKey = ApiKey.apiKey;
  final String baseUrl = "https://developers.themoviedb.org/3";
  final String baseImageUrl = "https://image.tmdb.org/t/p/w500/";
  final String baseVideoUrl = "https://www.youtube.com/watch?=v";
}

ApiKey

class ApiKey {
  static String apiKey = "my_api_key";
}

ApiService

class ApiService {
  final Api api = Api();
  final Dio dio = Dio();

  Future<Response> getData(String path, {Map<String, dynamic>? params}) async {
    String url = api.baseUrl   path;
    Map<String, dynamic> query = {
      "api_key": api.apiKey,
      "language": "en-US",
    };

    if(params != null) {
      query.addAll(params);
    }

    final response = await dio.get(url, queryParameters: query);

    if(response.statusCode == 200) {
      return response;
    }
    else {
      throw response;
    }
  }

  //****************************************************************************
  // Get popular movies
  //****************************************************************************

  Future getPopularMovies({required int pageNumber}) async{
    Response response = await getData(
        "/movie/popular",
        params: {
          "page": pageNumber,
        }
    );

    if(response.statusCode == 200){
      Map data = response.data; // <--------------------------- Problem is here
      List<dynamic> results = data["results"]; // <--------------------------- And here
      List<Movie> movies = [];

      for(Map<String, dynamic> json in results){
        Movie movie = Movie.fromJson(json);
        movies.add(movie);
      }
      return movies;
    }
    else{
      throw response;
    }
  }
}

HomeScreen

class HomeScreen extends StatefulWidget {
  const HomeScreen({Key? key}) : super(key: key);

  @override
  State<HomeScreen> createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  List<Movie>? movies;

  @override
  void initState() {
    super.initState();
    getMovies();
  }

  //****************************************************************************
  // Get movies
  //****************************************************************************

  void getMovies(){
    ApiService().getPopularMovies(pageNumber: 1)
        .then((movieList){
          setState(() {
            movies = movieList;
          });
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: kBackgroundColor,
      appBar: AppBar(
        backgroundColor: kBackgroundColor,
        leading: Image.asset(
          "assets/images/netflix_logo_2.png"
        ),
      ),
      body: ListView(
        children: [
          Container(
            height: 500,
            color: Colors.red,
            child: movies == null
                ? const Center()
                : Image.network(
                    movies![0].posterUrl(),
                    fit: BoxFit.cover,
            ),
          ),
          const SizedBox(height: 15,),
          Text("Current trends",
            style: GoogleFonts.poppins(
                color: Colors.white,
                fontSize: 18,
                fontWeight: FontWeight.bold
            ),
          ),
          const SizedBox(height: 5,),
          SizedBox(
            height: 160,
            child: ListView.builder(
              scrollDirection: Axis.horizontal,
              itemCount: 10,
              itemBuilder: (context, index) {
                return Container(
                  width: 110,
                  margin: const EdgeInsets.only(right: 8),
                  color: Colors.yellow,
                  child: Center(
                    child: Text(index.toString()),
                  ),
                );
              },
            ),
          ),
          const SizedBox(height: 15,),
          Text("Currently in cinema",
            style: GoogleFonts.poppins(
                color: Colors.white,
                fontSize: 18,
                fontWeight: FontWeight.bold
            ),
          ),
          const SizedBox(height: 5,),
          SizedBox(
            height: 320,
            child: ListView.builder(
              scrollDirection: Axis.horizontal,
              itemCount: 10,
              itemBuilder: (context, index) {
                return Container(
                  width: 220,
                  margin: const EdgeInsets.only(right: 8),
                  color: Colors.blue,
                  child: Center(
                    child: Text(index.toString()),
                  ),
                );
              },
            ),
          ),
          const SizedBox(height: 15,),
          Text("Available soon",
            style: GoogleFonts.poppins(
                color: Colors.white,
                fontSize: 18,
                fontWeight: FontWeight.bold
            ),
          ),
          const SizedBox(height: 5,),
          SizedBox(
            height: 160,
            child: ListView.builder(
              scrollDirection: Axis.horizontal,
              itemCount: 10,
              itemBuilder: (context, index) {
                return Container(
                  width: 110,
                  margin: const EdgeInsets.only(right: 8),
                  color: Colors.green,
                  child: Center(
                    child: Text(index.toString()),
                  ),
                );
              },
            ),
          ),
        ],
      ),
    );
  }
}

What I've tried:

I've tried to replace Map with var in ApiService but the problem isn't solved because another error is shown in the logcat doing this:

[ERROR:flutter/lib/ui/ui_dart_state.cc(198)] Unhandled Exception: type 'String' is not a subtype of type 'int' of 'index'

Thanks in advance for the help

CodePudding user response:

in the ApiService file first import

import 'dart:convert';

then in the same line where the problem occurred add jsonDecode, like this

Map data = jsonDecode(response.data);

CodePudding user response:

@hamza aboshhiwa thanks for the answer

I finally found, the 2 mistakes were in Movie and API replacing:

String posterUrl() {
    Api api = Api();

    return api.baseUrl   posterPath!;
  }

By:

String posterUrl() {
    Api api = Api();

    return api.baseImageUrl   posterPath!;
  }

And:

class Api {
  final String apiKey = ApiKey.apiKey;
  final String baseUrl = "https://developers.themoviedb.org/3";
  final String baseImageUrl = "https://image.tmdb.org/t/p/w500/";
  final String baseVideoUrl = "https://www.youtube.com/watch?=v";
}

By:

class Api {
  final String apiKey = ApiKey.apiKey;
  final String baseUrl = "https://api.themoviedb.org/3"; //<-----------------
  final String baseImageUrl = "https://image.tmdb.org/t/p/w500/";
  final String baseVideoUrl = "https://www.youtube.com/watch?=v";
}

Now it works

  • Related