Overview
Aradia Audiobooks uses a hybrid state management approach combining:- BLoC (Business Logic Component) for screen-specific business logic
- Provider for global application state and services
- Hive for persistent local storage
State Management Strategy
BLoC
Screen-specific business logic with reactive streams
Provider
Global services and shared state across widgets
Hive
Persistent storage for offline data
BLoC Pattern
When to Use BLoC
Use BLoC for:- Screen-specific business logic
- Complex state transitions
- Asynchronous operations (API calls)
- Pagination and data fetching
- Search functionality
BLoC Architecture
Each BLoC consists of three parts:- Events - User actions or external triggers
- States - UI states representing different conditions
- BLoC - Business logic that transforms events into states
Search BLoC Example
Here’s how the Search feature is implemented:Home BLoC Example
The Home screen demonstrates multiple event handlers and state management:Using BLoC in Widgets
Providing and consuming BLoC in the widget tree:Provider Pattern
When to Use Provider
Use Provider for:- Global services (audio player, theme, settings)
- Shared state across multiple screens
- Dependency injection
- Simple state that doesn’t require complex logic
Global Providers
Aradia uses several global providers:Audio Handler Provider
Manages the audio service for background playback:Theme Notifier
Manages app theme with persistent storage:Hive Storage
Initialization
Hive boxes are initialized at app startup:lib/main.dart
Using Hive
Best Practices
BLoC Best Practices
BLoC Best Practices
- One BLoC per screen - Keep BLoCs focused on a single responsibility
- Clean up subscriptions - Always cancel StreamSubscriptions in
close() - Immutable events and states - Use
@immutableand final fields - Sealed classes - Use sealed classes for events and states in Dart 3.0+
- Handle all states - Ensure UI handles all possible states
- Avoid business logic in UI - Keep widgets focused on presentation
Provider Best Practices
Provider Best Practices
- Dispose resources - Override
dispose()to clean up - Minimize rebuilds - Use
ConsumerorSelectorinstead ofcontext.watch() - Use
context.read()for actions - Don’t usecontext.watch()for one-time actions - Lazy initialization - Use
lazy: truefor providers not needed at startup - Combine with BLoC - Use Provider for services, BLoC for business logic
Hive Best Practices
Hive Best Practices
- Initialize early - Open boxes before
runApp() - Use descriptive names - Name boxes clearly (e.g.,
favourite_audiobooks_box) - Type safety - Use
Box<T>with typed models when possible - Compact regularly - Call
box.compact()to optimize storage - Avoid large objects - Store only necessary data
- Use adapters for complex types - Register custom type adapters
State Flow Diagram
Testing State Management
Common Patterns
Pagination with BLoC
Error Handling
Next Steps
Architecture
Learn about the overall app architecture
Building from Source
Set up your development environment
Contributing
Start contributing to the project