Flutter type 'List<dynamic>' is not a subtype of type 'List<Movie>'を解決したい
目的
Vueで映画情報の検索がようやくできた。。
— 高卒プログラマーげんと (@gento34165638) October 1, 2020
社会人ってこんなに忙しんや。。。作りたいアプリを作る時間がこんなに無いとは、先が思いやられる。😭#プログラミング #エンジニア pic.twitter.com/GEUoDZ2iMV
このように映画のAPI(TMDB API)を使って、映画を検索できるようにしたいです。
また、どのように実装すれば良いのか良くわからないので、とりあえずこちらを参考にしてChangeNotifierProvider
とConsumer
を使っています。
発生してるエラー
検索用のTextField
に文字を入れて、検索をかけるとエラーが発生します。。。
type 'List<dynamic>' is not a subtype of type 'List<Movie>'
— 高卒プログラマーげんと (@gento34165638) April 7, 2021
こういう型のエラーがマジで意味不明なんですが、、、
一体どこを見れば良いのでしょうか??😟 pic.twitter.com/fBDbQgpVvp
flutter: type 'List<dynamic>' is not a subtype of type 'List<Movie>'
このように型のエラーが発生しています。。
該当のソースコード
※全てのソースは下記にあります。
検索画面
import 'package:flutter/material.dart';
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:provider/provider.dart';
import '../config.dart';
import '../widgets/movie_card.dart';
import '../providers/search_movie.dart';
import '../providers/movie.dart';
class SearchMovieScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
final moviesData = Provider.of<SearchMovie>(context);
final searchedMovies = moviesData.movies;
return ChangeNotifierProvider<SearchMovie>(
create: (_) => SearchMovie(),
child: Consumer<SearchMovie>(
builder: (context, model, child) {
return Scaffold(
body: Container(
child: Column(
children: <Widget>[
TextField(
onChanged: (inputText) {
print(inputText);
model.text = inputText;
model.search();
},
decoration: InputDecoration(
prefixIcon: Icon(
Icons.search,
color: Colors.grey,
),
hintText: 'タイトルを入れてね'),
),
Expanded(
child: ListView.builder(
scrollDirection: Axis.vertical,
itemCount: model.movies.length,
itemBuilder: (BuildContext context, int index) {
return Container(
padding: EdgeInsets.all(20),
child: Column(
children: <Widget>[
MovieCard(
searchedMovies[index].title,
searchedMovies[index].releaseDate,
searchedMovies[index].overview,
searchedMovies[index].posterPath,
),
],
),
);
}),
)
],
)),
);
},
),
);
}
}
型を決めているMovie class
import 'package:flutter/material.dart';
class Movie with ChangeNotifier {
int voteCount;
int id;
bool video;
num voteAverage;
String title;
double popularity;
String posterPath;
String originalLanguage;
String originalTitle;
String backdropPath;
bool adult;
String overview;
String releaseDate;
Movie({
this.voteCount,
this.id,
this.video,
this.voteAverage,
this.title,
this.popularity,
this.posterPath,
this.originalLanguage,
this.originalTitle,
this.backdropPath,
this.adult,
this.overview,
this.releaseDate,
});
// 参考にしたコードに書いてあったが、どうやって使うのかわからない。。。
static Movie fromJson(Map<String, dynamic> json) {
return Movie(
voteCount: json['vote_count'],
id: json['id'],
video: json['video'],
voteAverage: json['vote_average'],
title: json['title'],
popularity: json['popularity'],
posterPath: json['poster_path'],
originalLanguage: json['original_language'],
originalTitle: json['original_title'],
backdropPath: json['backdrop_path'],
adult: json['adult'],
overview: json['overview'],
releaseDate: json['release_date'],
);
}
}
検索した時に値の変更を知らせるSearchMovie class
import 'package:flutter/material.dart';
import 'dart:convert';
import 'package:http/http.dart' as http;
import '../config.dart';
import './movie.dart';
class SearchMovie with ChangeNotifier {
String text = '';
List<Movie> _movies = [];
List<Movie> get movies {
return [..._movies];
}
search() async {
if (this.text.isNotEmpty) {
var searchUrl =
'${MOVIE_DB_BASE_URL}/search/movie?api_key=${API_KEY}&language=en-US&query=${text}&page=1';
try {
final response = await http.get(searchUrl);
final List<Movie> extractedData = json.decode(response.body)['results'];
if (extractedData == null) {
print('nothing to get');
return;
}
_movies = extractedData;
notifyListeners();
} catch (error) {
print(error);
throw (error);
}
}
}
}
把握している問題点
final List<Movie> extractedData = json.decode(response.body)['results'];
ここでjson.decode
して取得している値がList<dynamic>
になっているため、List<Movie>
に代入?できない。
ここを解決すると目指している実装ができるかは定かではないですが、とりあえずjson.decode
した物をどうやって別のclassの型に変換するのかがわからないです