前端转 Flutter 笔记 (Day 10.2):实战 - 用 Repository + HttpClient 写一个完整功能 🚀
摘要:前面讲了 Repository 模式和 HttpClient 封装,但都是分开讲的。 这篇短文把它们串起来,从头到尾写一个完整的"获取用户列表"功能。
目标 🎯
实现一个用户列表页面,数据从 REST API 获取。
Step 1: 定义 Model
dart
// lib/models/user.dart
class User {
final String id;
final String name;
final String email;
User({required this.id, required this.name, required this.email});
factory User.fromJson(Map<String, dynamic> json) {
return User(
id: json['id'] as String,
name: json['name'] as String,
email: json['email'] as String,
);
}
}Step 2: 定义 Repository 接口
dart
// lib/repositories/user_repository.dart
abstract class UserRepository {
Future<List<User>> getUsers();
}Step 3: 实现 Repository (调用 HttpClient)
dart
// lib/repositories/impl/rest_user_repository.dart
import 'package:my_flutter_app/net/http_client.dart';
import 'package:my_flutter_app/net/api_response.dart';
class RestUserRepository implements UserRepository {
final _dio = HttpClient().dio;
@override
Future<List<User>> getUsers() async {
final response = await _dio.get('/users');
final result = ApiResponse.fromJson(
response.data,
(data) => (data as List).map((e) => User.fromJson(e)).toList(),
);
if (result.isSuccess) {
return result.data ?? [];
}
throw Exception(result.message);
}
}Step 4: 注册 Provider
dart
// lib/providers/repository_providers.dart
@riverpod
UserRepository userRepository(UserRepositoryRef ref) {
return RestUserRepository();
}
@riverpod
Future<List<User>> userList(UserListRef ref) async {
final repo = ref.watch(userRepositoryProvider);
return repo.getUsers();
}Step 5: UI 使用
dart
// lib/pages/user_list_page.dart
class UserListPage extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final usersAsync = ref.watch(userListProvider);
return Scaffold(
appBar: AppBar(title: Text('用户列表')),
body: usersAsync.when(
loading: () => Center(child: CircularProgressIndicator()),
error: (err, _) => Center(child: Text('加载失败: $err')),
data: (users) => ListView.builder(
itemCount: users.length,
itemBuilder: (_, index) {
final user = users[index];
return ListTile(
title: Text(user.name),
subtitle: Text(user.email),
);
},
),
),
);
}
}完整调用链 🔗
UserListPage (UI)
│
│ ref.watch(userListProvider)
▼
userListProvider (ViewModel)
│
│ ref.watch(userRepositoryProvider)
▼
RestUserRepository (Repository)
│
│ HttpClient().dio.get('/users')
▼
Dio + Interceptors (Network)
│
│ HTTP Request
▼
Backend API → JSON Response关键点 ✅
- Model: 只管数据结构和 JSON 解析
- Repository 接口: 只定义"能做什么",不关心怎么做
- Repository 实现: 调用 HttpClient,处理响应格式
- Provider: 把 Repository 注入系统,管理状态
- UI: 只管渲染,用
.when()处理加载/错误/成功三种状态
为什么这么写?🤔
以后如果要:
- 换成 GraphQL:只需新建
GraphQLUserRepository,改一行注入代码 - 加本地缓存:在 Repository 实现里加,UI 和 Provider 不用动
- 写单元测试:Mock 一个
FakeUserRepository,不需要真网络请求
一句话总结:越往上层,知道的越少越好。UI 不知道数据从哪来,Repository 不知道数据怎么展示。
