---
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