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