Flutter Architecture
Flutter Architecture: Models, Providers, DAO, and Repositories
This document explains how models, providers, DAOs, and repositories work together in a Flutter app, and shows how data flows between layers.
1. Models
- Definition: Plain Dart classes that represent your app’s data.
- Purpose: Define the shape of data, often including JSON serialization methods.
class User {
final int 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'],
name: json['name'],
email: json['email'],
);
}
Map<String, dynamic> toJson() => {
'id': id,
'name': name,
'email': email,
};
}
2. DAO (Data Access Object)
- Definition: Encapsulates raw database queries.
- Purpose: Handles persistence logic, usually with SQLite/Drift.
@DriftAccessor(tables: [Users])
class UserDao extends DatabaseAccessor<AppDatabase> with _$UserDaoMixin {
UserDao(AppDatabase db) : super(db);
Future<List<User>> getAllUsers() => select(users).get();
Future<int> insertUser(User user) => into(users).insert(user);
}
3. Repository
- Definition: A single source of truth for data, sitting between data sources and the rest of the app.
- Purpose: Chooses between API and DAO, applies caching, and provides a unified interface.
class UserRepository {
final UserDao userDao;
final ApiService apiService;
UserRepository({required this.userDao, required this.apiService});
Future<List<User>> getUsers() async {
try {
final users = await apiService.fetchUsers();
await userDao.insertUsers(users);
return users;
} catch (_) {
return userDao.getAllUsers();
}
}
}
4. Provider
- Definition: A state management tool that exposes repositories to the UI.
- Purpose: Notifies widgets of changes and holds UI state.
class UserProvider with ChangeNotifier {
final UserRepository repository;
List<User> _users = [];
bool _loading = false;
List<User> get users => _users;
bool get loading => _loading;
UserProvider(this.repository);
Future<void> loadUsers() async {
_loading = true;
notifyListeners();
_users = await repository.getUsers();
_loading = false;
notifyListeners();
}
}
5. How They Work Together
+-------------------------+
| UI |
| (Widgets/Screens) |
+-----------+-------------+
|
| reads state / calls actions
v
+-------------------------+
| Provider |
| (ChangeNotifier, etc.) |
+-----------+-------------+
| uses
v
+-------------------------+
| Repository |
| (single source of truth|
| + orchestration) |
+-----+---------------+---+
| |
| chooses source|
v v
+-----------+ +---------+
| DAO | | API |
| (Local DB | | Client |
| / cache) | | (HTTP) |
+-----+-----+ +----+----+
| |
| maps to/from | maps to/from
v v
+-----------------------+
| Models |
| (User, Post, etc.) |
+-----------------------+
Request Flow
UI → Provider → Repository → (API or DAO) → Models → back to UI
Key Takeaways
- Models define the structure of data.
- DAO handles persistence logic.
- Repository abstracts data sources.
- Provider exposes data/state to the UI.
- UI remains reactive and unaware of data source details.