데이터 소스(2) - 완전한 영화 응용 프로그램
우리는 가장 좋은 인코딩 실천과 도구로 영화 응용 프로그램을 구축하고 있다.이전 영상에서 저는 우리의 폴더 구조가 어떻게 될지 설명했고 깨끗한 체계 구조 개념을 사용할 것입니다.
동영상 자습서의 부속 기사입니다.
TMDb API 키 만들기
영화를 보려면 TMDb API를 사용하므로 먼저 TMDb API 키를 만듭니다.https://www.themoviedb.org/login를 열고 사이트에 등록하거나 로그인합니다.
로그인하면 액세스https://www.themoviedb.org/settings/account를 통해 설정에 들어갈 수 있습니다.왼쪽 메뉴에서 API 섹션을 열고 API 키(v3 auth) 아래의 값을 복사합니다.또한 API 호출을 수행하려면 기본 URL이 필요하므로 예제 API 요청 URL을 읽어 보십시오.
프로젝트를 열고 api constants 파일을 생성합니다.데이터/core 폴더에 채널을 삽입하고 다음 코드를 배치합니다.
class ApiConstants {
//1
ApiConstants._();
//2
static const String BASE_URL = "https://api.themoviedb.org/3/";
//3
static const String API_KEY = "f33521953035af3fc3162fe1ac22e60c";
//4
static const String BASE_IMAGE_URL = "https://image.tmdb.org/t/p/w500";
}
BASE_IMAGE_URL
TMDb API 응답
https://developers.themoviedb.org/3/로 이동하고 왼쪽 메뉴에서 트렌드를 선택하세요.오른쪽에서 디테일을 볼 수 있습니다.너는 이것에 대해 더 많은 탐색을 할 수 있지만, 두 가지 매우 중요한 것은
media_type
과 time_window
이다.이것은 영화 프로그램이기 때문에 미디어 형식은 영화가 될 것입니다. 시간 창을 데이로 선택할 수 있습니다.평가판 탭을 열고 영화 제목media_type
, 날짜 제목time_window
을 선택한 다음 API 필드에 API 키를 넣습니다.이제 요청 보내기 버튼을 누르면 요청과 응답을 볼 수 있습니다.전체 URL을 읽고 기본 URL을 확인할 수 있습니다.이 응답을 복사하고dart모델을 만듭니다.https://javiercbk.github.io/json_to_dart/를 열고 응답을 텍스트 상자에 붙여넣습니다.클래스의 이름을 MoviesResultModel로 지정합니다.
dart 파일\u 결과\u 모델을 생성합니다.data/models 폴더에dart를 삽입하고 jsonToDart에서 생성한 코드를 붙여넣습니다.만든 필드를 보십시오.생성된 클래스는 영화 목록이 있습니다.페이지 나누기를 보여 주지 않기 때문에 페이지, totalPages, totalResults와 같은 페이지와 관련된 필드를 삭제할 수 있습니다.코드를 더욱 간소화하기 위해 이 파일에서
Results
클래스를 삭제하고 movie model이라는 단독 파일을 만들 수 있습니다.데이터/모델을 빠르게 입력합니다.다음은 두 가지 과정입니다.class MoviesResultModel {
final List<MovieModel> movies;
MoviesResultModel({this.page, this.movies});
factory MoviesResultModel.fromJson(Map<String, dynamic> json) {
List tempMovies = new List<MovieModel>();
if (json['results'] != null) {
json['results'].forEach((v) {
tempMovies.add(MovieModel.fromJson(v));
});
}
return MoviesResultModel(movies: tempMovies);
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
if (this.movies != null) {
data['results'] = this.movies.map((v) => v.toJson()).toList();
}
return data;
}
}
class MovieModel extends MovieEntity {
int id;
bool video;
int voteCount;
double voteAverage;
String title;
String releaseDate;
String originalLanguage;
String originalTitle;
List<int> genreIds;
String backdropPath;
bool adult;
String overview;
String posterPath;
double popularity;
String mediaType;
const MovieModel({
this.popularity,
this.voteCount,
this.video,
this.posterPath,
this.id,
this.adult,
this.backdropPath,
this.originalLanguage,
this.originalTitle,
this.genreIds,
this.title,
this.voteAverage,
this.overview,
this.releaseDate,
this.mediaType,
});
Results.fromJson(Map<String, dynamic> json) {
id = json['id'];
video = json['video'];
voteCount = json['vote_count'];
voteAverage = json['vote_average'];
title = json['title'];
releaseDate = json['release_date'];
originalLanguage = json['original_language'];
originalTitle = json['original_title'];
genreIds = json['genre_ids'].cast<int>();
backdropPath = json['backdrop_path'];
adult = json['adult'];
overview = json['overview'];
posterPath = json['poster_path'];
popularity = json['popularity'];
mediaType = json['media_type'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['popularity'] = this.popularity;
data['vote_count'] = this.voteCount;
data['video'] = this.video;
data['poster_path'] = this.posterPath;
data['id'] = this.id;
data['adult'] = this.adult;
data['backdrop_path'] = this.backdropPath;
data['original_language'] = this.originalLanguage;
data['original_title'] = this.originalTitle;
data['genre_ids'] = this.genreIds;
data['title'] = this.title;
data['vote_average'] = this.voteAverage;
data['overview'] = this.overview;
data['release_date'] = this.releaseDate;
data['media_type'] = this.mediaType;
return data;
}
}
의존 항목 2개 추가 - http 및 equatableequatable: ^1.2.0
http: ^0.12.1
dart에서 같은 플러그인을 사용할 때 대상을 비교하는 것이 더 쉽다.HTTP 플러그인은 네트워크 호출에 사용됩니다.화면에 모든 필드를 동시에 사용할 수 없기 때문에 프로그램에서 필요한 필드를 고려해 보세요.필요한 필드는 주로 id,posterPath,backdropPath,title,voteAverage,releaseDate,overview입니다.일부 필드는 여전히 불필요하지만, 우리가 가장 좋아하는 영화를 제작할 때, 당신은 이 시리즈의 뒷부분에서 그것들을 사용해야 합니다.
이제 domain/entities 폴더에 MovieEntity 클래스를 만들고 이 필드를 최종 필드로 선언합니다.Equatable로 이 종류를 확장합니다.id와 제목 필드를 사용하여 다시 쓰기
props
방법입니다.인쇄 대상에서 id와 제목을 볼 수 있도록 다시 쓰기 stringify
방법도 있습니다.MovieEntity 클래스는 다음과 같습니다.
import 'package:equatable/equatable.dart';
import 'package:flutter/foundation.dart';
class MovieEntity extends Equatable {
final String posterPath;
final int id;
final String backdropPath;
final String title;
final num voteAverage;
final String releaseDate;
final String overview;
const MovieEntity({
@required this.posterPath,
@required this.id,
@required this.backdropPath,
@required this.title,
@required this.voteAverage,
@required this.releaseDate,
this.overview,
}) : assert(id != null, 'Movie id must not be null');
@override
List<Object> get props => [id, title];
@override
bool get stringify => true;
}
MovieModel
와 MovieEntity를 정확하게 연결하고 깨끗한 구조를 실행하려면 MovieModel
확장MovieEntity
을 사용하십시오.이것은 영역과 데이터 층을 분리하는 데 도움이 될 것이다.현재
MovieModel
가 확장MovieEntity
되고 있으므로 변경해야 합니다.MovieModel
로 설정합니다.final
방법을 공장 방법으로 업데이트하고 fromJson
대상과 새로운 값을 부여하지 않고 직접 되돌려줍니다.MovieModel
구조 함수는 super
에 값을 부여한다.이렇게 하면 MovieEntity
를 언제 MovieModel
실례로 변환하든지 간에 정확한 비공식 값을 가진 필수 필드를 얻을 수 있다.MovieEntity
의 외관입니다.import '../../domain/entities/movie_entity.dart';
class MovieModel extends MovieEntity {
final double popularity;
final int voteCount;
final bool video;
final String posterPath;
final int id;
final bool adult;
final String backdropPath;
final String originalLanguage;
final String originalTitle;
final List<int> genreIds;
final String title;
final num voteAverage;
final String overview;
final String releaseDate;
final String mediaType;
const MovieModel({
this.popularity,
this.voteCount,
this.video,
this.posterPath,
this.id,
this.adult,
this.backdropPath,
this.originalLanguage,
this.originalTitle,
this.genreIds,
this.title,
this.voteAverage,
this.overview,
this.releaseDate,
this.mediaType,
}) : super(
id: id,
title: title,
backdropPath: backdropPath,
posterPath: posterPath,
releaseDate: releaseDate,
voteAverage: voteAverage,
overview: overview,
);
factory MovieModel.fromJson(Map<String, dynamic> json) {
return MovieModel(
popularity: json['popularity'],
voteCount: json['vote_count'],
video: json['video'],
posterPath: json['poster_path'],
id: json['id'],
adult: json['adult'],
backdropPath: json['backdrop_path'],
originalLanguage: json['original_language'],
originalTitle: json['original_title'],
genreIds: json['genre_ids'].cast<int>(),
title: json['title'],
voteAverage: json['vote_average'],
overview: json['overview'],
releaseDate: json['release_date'],
mediaType: json['media_type'],
);
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['popularity'] = this.popularity ;
data['vote_count'] = this.voteCount;
data['video'] = this.video;
data['poster_path'] = this.posterPath;
data['id'] = this.id;
data['adult'] = this.adult;
data['backdrop_path'] = this.backdropPath;
data['original_language'] = this.originalLanguage;
data['original_title'] = this.originalTitle;
data['genre_ids'] = this.genreIds;
data['title'] = this.title;
data['vote_average'] = this.voteAverage;
data['overview'] = this.overview;
data['release_date'] = this.releaseDate;
data['media_type'] = this.mediaType;
return data;
}
}
When you're declaring any field as double in models, be completely sure that it'll always be returned as double. If it is returned as an int, convert library fails to parse it. Either you can declare this as num or use toDouble function with safe operators.
json['popularity']?.toDouble() ?? 0.0
This will parse
int
todouble
ifint
is returned from API. As well as, if it is returned asnull
, 0.0 will be the default value ofpopularity
.Additionally, you can assign more default values to all the model fields.
데이터 소스 만들기
이제 모형과 실체를 채우기 위해 인터넷 전화에 집중합시다.
Create a file movie_remote_data_source.dart in data/data_sources folder.
Create an abstract class MovieRemoteDataSource with one function as of now. This method will call TMDb API for trending movies by day.
abstract class MovieRemoteDataSource {
Future<List<MovieModel>> getTrending();
}
같은 파일에 추상 클래스 추가class MovieRemoteDataSourceImpl extends MovieRemoteDataSource {
@override
Future<List<MovieModel>> getTrending() async {
//TODO: Fetch Trending Movies
}
}
맨 위에 마지막 필드 MovieModel
를 설명하고 http 패키지의 실례 _client
를 사용하여 MovieRemoteDataSource
의 구조 함수를 만듭니다.class MovieRemoteDataSourceImpl extends MovieRemoteDataSource {
final Client _client;
MovieRemoteDataSourceImpl(this._client);
}
다채로운 영화를 보다.
현재, 우리는
Client
를 사용하여 유행 영화를 위해 get API를 호출할 것이다.@override
Future<List<MovieModel>> getTrending() async {
final response = await _client.get(
//1
'${ApiConstants.BASE_URL}trending/movie/day?api_key=${ApiConstants.API_KEY}',
//2
headers: {
'Content-Type': 'application/json',
},
);
//3
if (response.statusCode == 200) {
//4
final responseBody = json.decode(response.body);
//5
final movies = MoviesResultModel.fromJson(responseBody).movies;
print(movies);
//6
return movies;
} else {
//7
throw Exception(response.reasonPhrase);
}
}
_client
공장 방법으로 모델에 대한 JSON 응답을 분석할 것이다.영화 목록이 하나밖에 없기 때문에 해석한 후에 fromJson
에서만 영화를 얻을 수 있습니다GetTrending 함수 호출
UI를 만들지 않기 전에, Google 네트워크 호출이 정상적으로 작동하고,main에서 직접 호출해서 원하는 결과를 제공할 수 있습니다.던지다.
주관도를 열다.
MovieResultModel
를 호출하기 전에 다음 코드 세그먼트runApp(MyApp())
함수를 호출할 수 있습니다.//1
MovieRemoteDataSource dataSource = MovieRemoteDataSourceImpl(Client());
//2
dataSource.getTrending();
getTrending()
.Client
와 id
가 포함된 영화 목록을 볼 수 있습니다. title
에서 id와 제목을 전달했기 때문입니다.인기 영화 를 얻다
API 호출을 빠르게 추가합니다.팝 영화를 얻기 위해 다른 API를 호출하는 getPopular 함수를 만듭니다.다음과 같이 추상 클래스에
props
를 추가합니다.abstract class MovieRemoteDataSource {
Future<List<MovieModel>> getTrending();
Future<List<MovieModel>> getPopular();
}
집행getPopular()
방법은 다음과 같다.다행히도 URL 경로만 바뀌는 것이 유행하고 있다.@override
Future<List<MovieModel>> getPopular() async {
final response = await _client.get(
'${ApiConstants.BASE_URL}movie/popular?api_key=${ApiConstants.API_KEY}',
headers: {
'Content-Type': 'application/json',
},
);
if (response.statusCode == 200) {
final responseBody = json.decode(response.body);
final movies = MoviesResultModel.fromJson(responseBody).movies;
print(movies);
return movies;
} else {
throw Exception(response.reasonPhrase);
}
}
이 방법은main에서 호출getPopular()
하는 방식으로 실행할 수 있습니다.던지다.핵심 API 클라이언트
비록 지금까지 우리는 두 가지 방법만 추가했지만, 당신은 이미 중복된 코드를 보았을 것입니다.그래서 공공 코드를 단독 파일로 옮겨 봅시다.
api 클라이언트를 만듭니다.데이터/코어를 삽입합니다.
ApiClient 클래스에서 클라이언트를 고유한 최종 필드로 추가하고 이를 사용하여 구조 함수를 작성합니다.
class ApiClient {
final Client _client;
ApiClient(this._client);
}
모든 종류의 모델을 되돌릴 수 있기 때문에dynamic로 되돌아오는 get 방법을 만듭니다.dynamic get(String path) async {
final response = await _client.get(
'${ApiConstants.BASE_URL}$path?api_key=${ApiConstants.API_KEY}',
headers: {
'Content-Type': 'application/json',
},
);
if (response.statusCode == 200) {
return json.decode(response.body);
} else {
throw Exception(response.reasonPhrase);
}
}
우리는 이미 대부분의 코드를 이 방법으로 옮겼는데, 현재 우리는 매우 간단한 코드로 데이터 원본을 업데이트하여 실현할 수 있다.이제 클라이언트가 아닌 ApiClient가 사용됩니다.class MovieRemoteDataSourceImpl extends MovieRemoteDataSource {
//1
final ApiClient _client;
MovieRemoteDataSourceImpl(this._client);
@override
Future<List<MovieModel>> getTrending() async {
//2
final response = await _client.get('trending/movie/day');
return MoviesResultModel.fromJson(response).movies;
}
@override
Future<List<MovieModel>> getPopular() async {
//3
final response = await _client.get('movie/popular');
return MoviesResultModel.fromJson(response).movies;
}
}
getTrending()
방법.get
방법을 사용합니다.이 글은 최초로 발표되었다Medium
만약 네가 이 문장 중의 어떤 것을 좋아한다면 나를 따라오는 것을 잊지 마라🙏🏻. 너는 나에게 연락해서 따라와도 된다. GitHub
Reference
이 문제에 관하여(데이터 소스(2) - 완전한 영화 응용 프로그램), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/prateeksharma1712/datasources-2-complete-movie-app-3p8e텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)