최근 스타트업에 지원하였는데, Flutter BLOC 패턴을 사용한다 하여 공부를 진행하였다.
lib
| main.dart
|
\---src
| app.dart
|
+---blocs
| movies_bloc.dart
|
+---models
| item_model.dart
|
+---resources
| movie_api_provider.dart
| repository.dart
|
\---ui
moive_list.dart
ui
- ui적으로 보여지는 부분만 코딩
- bloc을 통해 데이터를 가져옴
class MovieList extends StatelessWidget {
Widget build(BuildContext context) {
bloc.fetchAllMovies(); // 영화 데이터를 가져오는 메서드 실행
return Scaffold(
appBar: AppBar(
title: Text('Popular Movies'),
),
body: StreamBuilder(
stream: bloc.allMovies,
builder: (context, AsyncSnapshot<ItemModel> snapshot) {
if (snapshot.hasData) {
return buildList(snapshot);
} else if (snapshot.hasError) {
return Text(snapshot.error.toString());
}
return Center(child: CircularProgressIndicator());
},
),
);
}
bloc
- ui에 데이터를 전달하는 역할
rxdart에 대한 사용법은 추후에 다른 글에서 정리하고 Bloc에 대한 내용만 기재
import '../resources/repository.dart';
import 'package:rxdart/rxdart.dart';
import '../models/item_model.dart';
class MoviesBloc {
final _repository = Repository();
final _moviesFetcher = PublishSubject<ItemModel>();
Stream<ItemModel> get allMovies => _moviesFetcher.stream;
fetchAllMovies() async {
ItemModel itemModel = await _repository.fetchAllMovies();
_moviesFetcher.sink.add(itemModel);
}
dispose() {
_moviesFetcher.close();
}
}
final bloc = MoviesBloc();
resources
repository MovieApiProvider
- API,DB를 활용하여 데이터를 직접적으로 가져오고, Bloc에 넘겨줌
import 'dart:async';
import 'movie_api_provider.dart';
import '../models/item_model.dart';
class Repository {
final moviesApiProvider = MovieApiProvider();
Future<ItemModel> fetchAllMovies() => moviesApiProvider.fetchMovieList();
}
import 'dart:async';
import 'package:http/http.dart' show Client;
import 'dart:convert';
import '../models/item_model.dart';
class MovieApiProvider {
Client client = Client();
final _apiKey = apikey;
Future<ItemModel> fetchMovieList() async {
print("entered");
var url = Uri.https(
'api.themoviedb.org',
'3/movie/popular',
{
'q': '{http}',
'api_key': _apiKey,
},
);
final response = await client.get(url);
print(response.body.toString());
if (response.statusCode == 200) {
// If the call to the server was successful, parse the JSON
return ItemModel.fromJson(json.decode(response.body));
} else {
// If that call was not successful, throw an error.
throw Exception('Failed to load post');
}
}
}
Models
- 데이터, getter, setter를 정의함
class ItemModel {
int _page;
int _total_results;
int _total_pages;
List<_Result> _results = [];
ItemModel.fromJson(Map<String, dynamic> parsedJson) {
print(parsedJson['results'].length);
_page = parsedJson['page'];
_total_results = parsedJson['total_results'];
_total_pages = parsedJson['total_pages'];
List<_Result> temp = [];
for (int i = 0; i < parsedJson['results'].length; i++) {
_Result result = _Result(parsedJson['results'][i]);
temp.add(result);
}
_results = temp;
}
List<_Result> get results => _results;
int get total_pages => _total_pages;
int get total_results => _total_results;
int get page => _page;
}
class _Result {
int _vote_count;
int _id;
bool _video;
var _vote_average;
String _title;
double _popularity;
String _poster_path;
String _original_language;
String _original_title;
List<int> _genre_ids = [];
String _backdrop_path;
bool _adult;
String _overview;
String _release_date;
_Result(result) {
_vote_count = result['vote_count'];
_id = result['id'];
_video = result['video'];
_vote_average = result['vote_average'];
_title = result['title'];
_popularity = result['popularity'];
_poster_path = result['poster_path'];
_original_language = result['original_language'];
_original_title = result['original_title'];
for (int i = 0; i < result['genre_ids'].length; i++) {
_genre_ids.add(result['genre_ids'][i]);
}
_backdrop_path = result['backdrop_path'];
_adult = result['adult'];
_overview = result['overview'];
_release_date = result['release_date'];
}
String get release_date => _release_date;
String get overview => _overview;
bool get adult => _adult;
String get backdrop_path => _backdrop_path;
List<int> get genre_ids => _genre_ids;
String get original_title => _original_title;
String get original_language => _original_language;
String get poster_path => _poster_path;
double get popularity => _popularity;
String get title => _title;
double get vote_average => _vote_average;
bool get video => _video;
int get id => _id;
int get vote_count => _vote_count;
}
Provider vs Bloc
프로바이더가 직관적이고 사용이 더 용이한것 같음
Bloc은 세심한 컨트롤이 필요한 대규모 프로젝트에 더 적합한듯 하다.