Skip to main content

route-observer-mixin-route-awareness

Use when tracking Flutter screen navigation lifecycle events (screen focus, push, pop, backgrounding) using route_observer_mixin without boilerplate subscription management.

Jump to install

Source facts

Repository
mono0926/route_observer_mixin
Last source activity
September 9, 2026 at 03:05
Detected SKILL.md language
English
Stars
26
Forks
5

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
route_observer_mixin-route-awareness
description
Use when tracking Flutter screen navigation lifecycle events (screen focus, push, pop, backgrounding) using route_observer_mixin without boilerplate subscription management.
# route_observer_mixin Screen Tracking Guide `route_observer_mixin` eliminates manual registration and disposal of Flutter `RouteObserver` and `RouteAware` subscriptions. It provides clean, declarative hooks for page lifecycle transitions (`didPush`, `didPop`, `didPushNext`, `didPopNext`). ## Guidelines - **Setup in Navigator**: - Wrap your app with `RouteObserverProvider` above `MaterialApp` (or provide it via `provider` / `riverpod`). - Pass `RouteObserverProvider.of(context)` (or the provider's instance) to `MaterialApp.navigatorObservers`. - **Implementing in State**: - Add `with RouteAware, RouteObserverMixin` to the target `State<MyWidget>` class. - Implement lifecycle methods: - `didPush()`: Called when the screen has been pushed and is now visible. - `didPopNext()`: Called when the top route has been popped off, and this screen becomes visible again. - `didPushNext()`: Called when a new route is pushed on top of this screen (this screen becomes obscured). - `didPop()`: Called when this screen has been popped off the navigator. - **Analytics & Tracking**: - Track screen views inside `didPush()` and `didPopNext()` to accurately capture when the user returns to a previously viewed page. - **Lifecycle Cleanup**: - Do not manually call `routeObserver.unsubscribe(this)`. `RouteObserverMixin` automatically manages subscription registration in `didChangeDependencies` and unsubscription in `dispose`. ## Examples ### 1. App Setup ```dart import 'package:flutter/material.dart'; import 'package:route_observer_mixin/route_observer_mixin.dart'; void main() { runApp( RouteObserverProvider( child: const MyApp(), ), ); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( navigatorObservers: [ RouteObserverProvider.of(context), ], home: const HomeScreen(), ); } } ``` ### 2. Page Implementation with Analytics Tracking ```dart import 'package:flutter/material.dart'; import 'package:route_observer_mixin/route_observer_mixin.dart'; class HomeScreen extends StatefulWidget { const HomeScreen({super.key}); @override State<HomeScreen> createState() => _HomeScreenState(); } class _HomeScreenState extends State<HomeScreen> with RouteAware, RouteObserverMixin { @override void didPush() { super.didPush(); // Screen is pushed for the first time _trackScreenView(); } @override void didPopNext() { super.didPopNext(); // User returned back to this screen from a pushed page _trackScreenView(); _refreshContent(); } @override void didPushNext() { super.didPushNext(); // Another screen was pushed on top of this screen _pauseMediaPlayback(); } void _trackScreenView() { debugPrint('Analytics: Screen viewed -> HomeScreen'); } void _refreshContent() { debugPrint('Refreshing active screen data'); } void _pauseMediaPlayback() { debugPrint('Pausing background video/audio'); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('Home')), body: Center( child: ElevatedButton( onPressed: () => Navigator.of(context).push( MaterialPageRoute(builder: (_) => const DetailScreen()), ), child: const Text('Go to Details'), ), ), ); } } class DetailScreen extends StatelessWidget { const DetailScreen({super.key}); @override Widget build(BuildContext context) => Scaffold( appBar: AppBar(title: const Text('Details')), ); } ``` ## Common Pitfalls & Anti-Patterns - ❌ **Anti-pattern**: Manually managing `RouteObserver().subscribe(this, ModalRoute.of(context)!)` inside `didChangeDependencies`, which frequently leaks subscriptions if unsubscription is missed in `dispose`. - ✔️ **Correct**: Use `RouteObserverMixin`, which handles registration and unsubscription safely and deterministically. - ❌ **Anti-pattern**: Only tracking screen view analytics in `initState`, which fails to capture when users navigate back to the page via the back button. - ✔️ **Correct**: Track screen views in both `didPush()` and `didPopNext()`.
View on GitHub