--- title: 'Flutter MVVM' tags: Flutter disqus: hackmd --- <style> .red { color: red; } .blue { color: blue; } </style> <font size="6">Flutter MVVM</font> **目錄:** [TOC] ## MVVM 這邊用Http範例來實作MVVM架構 ### Mdoel - json.dart ```dart= // Response class Album { final int? userId; final int id; final String title; const Album({ required this.userId, required this.id, required this.title, }); factory Album.fromJson(Map<String, dynamic> json) { return Album( userId: json['userId'], id: json['id'], title: json['title'], ); } } ``` - api_response.dart ```dart= class ApiResponse<T> { Status status; T? data; String? message; ApiResponse.initial(this.message) : status = Status.initial; ApiResponse.loading(this.message) : status = Status.loading; ApiResponse.completed(this.data) : status = Status.completed; ApiResponse.error(this.message) : status = Status.error; @override String toString() { return "Status : $status \n Message : $message \n Data : $data"; } } enum Status { initial, loading, completed, error } ``` ### ViewMode - album_provider.dart ```dart= class AlbumProvider with ChangeNotifier { ApiResponse _apiResponse = ApiResponse.initial('Empty data'); ApiResponse get response { return _apiResponse; } fetchAlbumData(String title) { APIRequest apiRequest = FetchAlbumRequest(title); decodeJson(apiRequest); } createAlbumData(String title) { APIRequest apiRequest = CreateAlbumRequest(title); decodeJson(apiRequest); } decodeJson(APIRequest apiRequest) async { _apiResponse = ApiResponse.loading('Create album data'); notifyListeners(); try { dynamic json = await HttpService().send(apiRequest); final album = Album.fromJson(json); _apiResponse = ApiResponse.completed(album); } catch (e) { _apiResponse = ApiResponse.error(e.toString()); debugPrint(e.toString()); } notifyListeners(); } } ``` ### View - main.dart ```dart= class HomeScreen extends StatelessWidget { final _controller = TextEditingController(); /// Constructs a [HomeScreen] HomeScreen({super.key}); @override Widget build(BuildContext context) { debugPrint('HomeScreen build'); final viewModel = Provider.of<AlbumProvider>(context, listen: false); // 等待畫面初始化完成 WidgetsBinding.instance.addPostFrameCallback((_) { viewModel.fetchAlbumData('1'); }); return Scaffold( appBar: AppBar(title: const Text('Home Screen')), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ SizedBox( width: 200, child: TextField( controller: _controller, decoration: const InputDecoration(hintText: 'Enter Title'), ), ), const SizedBox(height: 10), ElevatedButton( onPressed: () { viewModel.createAlbumData(_controller.text); }, child: const Text('send createAlbumRequest'), ), Consumer<AlbumProvider>( builder: (context, value, child) { debugPrint(value.response.status.toString()); // print switch (value.response.status) { case Status.error: return const FlutterLogo(); case Status.completed: Album data = value.response.data; return Text(data.title); default: return const CircularProgressIndicator(); } }, ) ], ), ), ); } } ``` ## Demo https://github.com/imacuser111/flutter-http-mvvm-example