Kiến trúc MVP trong Flutter – MVP Flutter Pattern
Kiến trúc MVP trong Flutter là một trong những pattern để xây dựng ứng dụng di động Flutter. Để hiểu rõ hơn về cách xây dựng của kiến trúc này, bạn cùng xem bài viết này.
Kiến trúc MVP trong Flutter
MVP viết tắt của : Model – View – Presenter
Model
Cũng giống như các mô hình khác như : MVC, MVVM,
Model đại diện cho một tập hợp các lớp mô tả business logic (business model and the data model)
View
View là thành phần tương tác trực tiếp với người dùng. Nó không bao gồm bất kỳ việc xử lý logic nào.
Presenter
Presenter sẽ nhận input của người dùng thông qua View, rồi xử lý dữ liệu của người dùng với sự trợ giúp của Model và trả kết quả về View. Presenter giao tiếp với View qua interface.
Interface được định nghĩa trong lớp Presenter (với cái nó cần truyền dữ liệu).
Trong cấu trúc MVP, presenter thao túng model và cập nhật ở view.
View và Presenter tách biệt với nhau hoàn toàn và giao tiếp với nhau qua thông qua interface.
Vì nếu tách riêng từng phần ở view sẽ dễ dàng cho việc kiểm thử ứng dụng ở MVP hơn
so với mô hình MVC.
Triển khai MVP trong Flutter
Để triển khai kiến trúc này, chúng ta có thể tự xây dựng cấu trúc MVP hoặc sử dụng thư viện đã có sẵn.
Tuy nhiên trong Flutter cũng có thư viện để thực hiện mô hình này như mvp nhưng không được phổ biến.
Vì vậy trong phần này chúng ta sẽ tự code để thực hiện kiến trúc này.
Tạo một project và có các file như bên dưới
Tạo Model trong folder : models
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
class User { Name? name; Picture? picture; String? email; String? phone; User({this.name, this.picture, this.email, this.phone}); User.fromJson(Map<String, dynamic> json) : name = new Name.fromJson(json['name']), picture = new Picture.fromJson(json['picture']), email = json['email'], phone = json['phone']; @override String toString() { // TODO: implement toString return phone! + " " + email! + " " + name!.first!; } } class Name { String? last; String? first; Name({this.last, this.first}); Name.fromJson(Map<String, dynamic> json) : last = json['last'], first = json['first']; } class Picture { String? medium; Picture({this.medium}); Picture.fromJson(Map<String, dynamic> json) : medium = json['large']; } |
Xử lý Data với Model : tạo repository
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
abstract class UserListRepository { Future<List<User>> fetchUser(); } class UserListRepositoryIml implements UserListRepository { @override Future<List<User>> fetchUser() { return http .get(API_USER_LIST) .then((http.Response response) { final String jsonBody = response.body; final int statusCode = response.statusCode; if(statusCode != 200 || jsonBody == null){ print(response.reasonPhrase); throw new FetchDataException("StatusCode:$statusCode, Error:${response.reasonPhrase}"); } final JsonDecoder _decoder = new JsonDecoder(); final useListContainer = _decoder.convert(jsonBody); final List userList = useListContainer['results']; return userList.map((contactRaw) => new User.fromJson(contactRaw)).toList(); }); } } |
Xử lý Data với Model : tạo injection
1 2 3 4 5 6 7 8 |
class Injector { static final Injector _singleton = new Injector._internal(); factory Injector() { return _singleton; } Injector._internal(); UserListRepository getUserListRepository() => new UserListRepositoryIml(); } |
Tạo presenter trong folder: presenters
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
abstract class UserListViewContract { void onLoadUserComplete(List<User> users); void onLoadUserError(); } class UserListPresenter { UserListViewContract? _view; UserListRepository? _repository; UserListPresenter(this._view) { _repository = new Injector().getUserListRepository(); } void loadUser() { assert(_view != null && _repository != null); _repository! .fetchUser() .then((contacts) => _view!.onLoadUserComplete(contacts)) .catchError((onError) => _view!.onLoadUserError()); } } |
Hiển thị lên View trong folder: views
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
class UserListState extends State<UserListScreen> implements UserListViewContract { UserListPresenter? _userListPresenter; List<User> users = []; bool isLoadingData = true; @override void initState() { _userListPresenter = new UserListPresenter(this); _userListPresenter!.loadUser(); } @override Widget build(BuildContext context) { return new Scaffold( appBar: new AppAppBar("Users"), body: _createBodyView(), ); } Widget _createBodyView() { if (isLoadingData) { return new Center( child: new CircularProgressIndicator( valueColor: new AlwaysStoppedAnimation<Color>(Colors.black), ), ); } return new ListView.builder( itemBuilder: (context, index) => new UserItem( user: users[index], callback: (users) => {}, ), itemCount: users.length, padding: new EdgeInsets.all(20.0), ); } @override void onLoadUserComplete(List<User> users) { setState(() { this.users = users; isLoadingData = false; }); } @override void onLoadUserError() { setState(() { isLoadingData = false; users = []; }); } } |
SOURCE CODE => MVP – Link Github
MVP trong Flutter là một trong những kiến trúc trong lập trình Flutter, Tuy nhiên hiện nay những kiến trúc riêng của Flutter như Bloc, Redux.. sẽ luôn được ưu tiên hơn. Rất cảm ơn bạn đã theo dõi.