This is a pattern I came up with when I was working on a fairly large one person app (25k LOC, legal/regulation calculator, lots of unit testing). It is very simple and very effective.
The short version is you have a RootStore that listens to all of it's child stores. Each store has an async initState method and a dispose method. Make observer mixins for platform channel related items like App Lifecycle, Geolocation, Geofencing that add more lifecycle methods to these stores and manage their own initState/dispose.
I realize that a gist is going to look like a bit of a cluster for something of this nature but I bet if you pull it all down into a project and start playing around with it you'll really enjoy it. Especially now that provider
has context.select
.
Here's an example of my folder structure in lib/features
as a bit of a bonus
lib/features
├── animations
│ └── animations_store.dart
├── announcements
│ ├── announcements_store.dart
│ ├── models
│ │ └── announcement.dart
│ └── widgets
│ ├── current_announcements.dart
│ └── section_announcement_notice.dart
├── atmosphere
│ ├── atmosphere_enums.dart
│ ├── atmosphere_slug.dart
│ ├── atmosphere_store.dart
│ ├── season_dates
│ │ ├── annual_season_dates.dart
│ │ ├── astronomical_season_dates.dart
│ │ └── wmd_season_dates.dart
│ └── widgets
│ ├── atmosphere_background.dart
│ └── atmosphere_debug_callout.dart
├── debug_controls
│ └── debug_controls.dart
├── geofencing
│ ├── geofencing_delorme_tiles.dart
│ ├── geofencing_extensions.dart
│ ├── geofencing_search_extensions.dart
│ ├── geofencing_store.dart
│ ├── geofencing_twp_extensions.dart
│ ├── geofencing_wmd_extensions.dart
│ └── widgets
│ ├── current_delorme_tile_callout.dart
│ ├── current_township_callout.dart
│ └── current_wmd_callout.dart
├── geolocation
│ ├── geolocation_constants.dart
│ ├── geolocation_service.dart
│ ├── geolocation_store.dart
│ └── widgets
│ └── geolocation_debug_controls.dart
├── hours
│ ├── hours_store.dart
│ ├── models
│ │ ├── hunting_day_model.dart
│ │ └── hunting_state_change_model.dart
│ ├── time_table_constants.dart
│ └── widgets
│ ├── hours_debug_controls.dart
│ ├── hours_progress_bar.dart
│ └── hunting_hours_chip.dart
├── onboarding
│ ├── onboarding_store.dart
│ ├── screens
│ │ └── onboarding_screen.dart
│ └── widgets
│ └── moose_season_cards_example.dart
├── permissions
│ ├── permissions_service.dart
│ ├── permissions_store.dart
│ └── widgets
│ ├── location_services_button.dart
│ ├── location_services_callout_section.dart
│ └── permissions_debug_controls.dart
├── persistance
│ ├── persistance_store.dart
│ └── widgets
│ ├── clear_app_data_button.dart
│ └── persistance_debug_controls.dart
├── reporting
│ └── reporting_store.dart
├── search
│ ├── search_extensions.dart
│ ├── search_none_found.dart
│ └── search_store.dart
├── seasons
│ ├── models
│ │ ├── day_of_year.dart
│ │ ├── day_of_year_range.dart
│ │ ├── season_model.dart
│ │ ├── species_seasons_result.dart
│ │ └── time_of_day_range.dart
│ ├── screens
│ │ └── seasons_available_screen.dart
│ ├── seasons_constants.dart
│ ├── seasons_filter_extensions.dart
│ ├── seasons_store.dart
│ └── widgets
│ ├── open_species_chip_cloud.dart
│ ├── season_cards.dart
│ ├── season_group_section.dart
│ └── upcoming_seasons.dart
├── species
│ ├── species_constants.dart
│ └── species_model.dart
├── store_observers
│ ├── app_lifecycle_observer.dart
│ ├── geolocation_change_observer.dart
│ └── location_permission_observer.dart
├── stores
│ ├── child_store.dart
│ ├── interval_rebuild.dart
│ ├── root_store.dart
│ ├── store.dart
│ ├── store_change_extension.dart
│ ├── store_change_observer.dart
│ ├── stores.dart
│ ├── stubbable_now.dart
│ └── stubbable_position.dart
├── svg_precache
│ └── svg_precache_store.dart
├── take
│ ├── take_constants.dart
│ └── take_model.dart
└── wmd
├── models
│ └── wmd_model.dart
├── screens
│ └── wmd_selection_screen.dart
├── widgets
│ └── wmd_radio_list_tile.dart
├── wmd_constants.dart
└── wmd_store.dart