월루를 꿈꾸는 대학생
[flutter] Provider 응용 (영화 앱) 본문
728x90
먼저 api가 필요함
TMDB에서 회원가입을 한 후
api 문서 홈페이지 접속
https://developers.themoviedb.org/3/movies/get-popular-movies
유명한 영화 순위를 받아 올거니까 해당 api를 사용한다
postman으로 리퀘스트 보내보고 확인
네비게이션 바텀 바 만들 때를 위해서 provider 가 하나 더 필요해짐
import 'package:flutter/material.dart';
class BottomNavigataionProvider extends ChangeNotifier {
int _index = 0;
int get currentPage => _index;
//1페이지인지 2페이지인지 파라미터로 받은 후 _index 값 변경하고 하위 위젯들에게 통보
updateCurrentPage(int index) {
_index = index;
notifyListeners();
}
}
원래는 하나의 프로바이더만 썼었는데 2개가 필요하니 변경
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: ChangeNotifierProvider(
// child 하위 모든 위젯들은 create에서 만든 객체에 접근이 가능
create: (BuildContext context) =>
CountProvider() /*{
return CountProvider();
}*/
,
child: Home(),
),
);
}
변경 후
home: MultiProvider(
// [] 안에 있는 리스트들은 하위 위젯이 참고 가능
providers: [
ChangeNotifierProvider(
create: (BuildContext context) => CountProvider()),
ChangeNotifierProvider(
create: (BuildContext context) => BottomNavigataionProvider()),
],
child: Home(),
),
하단 네비게이션 바
Widget _bottomNavigationBarWidget() {
return Consumer<BottomNavigationProvider>(
builder: (context, provider, widget) {
return BottomNavigationBar(
items: [
BottomNavigationBarItem(icon: Icon(Icons.home), label: 'home'),
BottomNavigationBarItem(icon: Icon(Icons.movie), label: 'movie'),
], // 현재 선택은 0으로 초기화
currentIndex: _bottomNavigationProvider!.currentPage,
selectedItemColor: Colors.red,
onTap: (index) {
// provider navigation state변경 ;
// 짜피 빌드 단에서 널체크 하니까 !
_bottomNavigationProvider!.updateCurrentPage(index);
},
);
});
}
컨슈머로 해당 위젯만 재빌드
상황에 따라 listen false를 쓸지 Consumer를 쓸지 선택해서 사용하면 됨
하단 네비게이션바에서 prvider index를 변경하면 이 변경한 걸 바라보는 위젯이 화면을 재빌드
Widget _navigationBody() {
// 해당 Home클래스 내부에 _bottomNavigationProvider으로 멤버 변수가 있으니까 어떤 위젯에서도 가져와서 사용이 가능
// 훨씬 편하네 ;;
switch(_bottomNavigationProvider!.currentPage){
case 0:
return CountHomeWidget();
break;
case 1:
return MovieListWidget();
break;
}
return Container();
}
영화 사이트에서 데이터를 받고 이를 활용할 모델 만들기
// api 요청에 의해 받은 값의 형태를 정의
// 이미지 poster_path, 제목 title, 설명이 필요 overview
class Movie {
String? overview;
String? posterPath;
String? title;
Movie({this.overview, this.posterPath, this.title});
//json으로 들어온 거를 파싱할 필요가 있음
//map 타입으로 들어옴
//factory 패턴
factory Movie.fromJson(Map<String, dynamic> json) {
// movie 객체 생성
return Movie(
// json 형태에서 overview로 파싱하고 문자열로 넣음
overview:json["overview"] as String,
posterPath:json["poster_path"] as String,
title:json["title"] as String,
);
}
String get posterUrl => "https://image.tmdb.org/t/p/w500/${this.posterPath}";
}
api 리퀘스트 후 값을 받아서 리스트로 리턴할 레파지토리
// api 서버 호출한 값을 받아오는 부분
import 'dart:convert';
import 'package:movie_app/const/api.dart';
import '../model/movie.dart';
import 'package:http/http.dart' as http;
class MovieRepository {
Future<List<Movie>> loadMovies() async {
var queryPram = {'api_key': '$apiKey'};
/// var uri = Uri.https('example.org', '/path', {'q': 'dart'});
/// print(uri); // https://example.org/path?q=dart
var uri =
Uri.https('api.themoviedb.org', '3/movie/popular', queryPram);
var response = await http.get(uri);
// 출력값이 있고
if (response.body != null) {
// 맵형태로 디코딩
Map<String, dynamic> body = json.decode(response.body);
// 결과값 있을 때
if (body["results"] != null) {
// map 으로 돌릴려면 개체로
List<dynamic> list = body["results"];
return list.map((e) => Movie.fromJson(e)).toList();
}
}
// 값 못 받은 경우 빈걸로
return [];
}
}
이를 프로바이더에서 movieRepository를 사용해서 사용할 데이터를 가공한 후 프로바이더를 바라보는 위젯이 이를 사요할 수 있도록
class MovieProvider extends ChangeNotifier {
MovieRepository _movieRepository = MovieRepository();
// response가 리스트 형태
List<Movie> _movies = [];
List<Movie> get movies => _movies;
loadMovies() async{
//repository 접근해서 데이터 불러오기
List<Movie> listMovies = await _movieRepository.loadMovies();
_movies=listMovies;
notifyListeners();
}
}
프로바이더의 데이터를 참조해서 화면을 빌드
body: Consumer<MovieProvider>(
builder: (context, provider, widget) {
if (provider.movies != null && provider.movies.length > 0) {
print(provider.movies.toString());
// 프로바이더에 있는 리스트를 넘김
return _makeListView(provider.movies);
}
//loadMovies 이거 호출을 안 한경우 null이니까 로딩바
return Center(
child: CircularProgressIndicator(),
);
},
),
주석 정리 및 전체 코드
https://github.com/suhyun96/Flutter/tree/main/provider/movie_app
출처
https://www.youtube.com/watch?v=Mf9eDfi-VhU&t=320s
728x90
'Programing > 플러터' 카테고리의 다른 글
[Firebase] Flutter Firebase 연동하기 (0) | 2022.12.15 |
---|---|
[firebase] 파이어베이스 개념 정리 / 세팅 (0) | 2022.12.14 |
[flutter] Provider 개념정리 - Count세기 (0) | 2022.12.12 |
[Flutter]Provider (0) | 2022.12.12 |
MVVM 패턴 (0) | 2022.12.08 |