Repository: flutter
Issue: WidgetsApp's backButtonDispatcher shouldn't be recreated every time
Labels: c: new feature,framework,f: routes,c: proposal,P2,team-framework,triaged-framework

## Use case
WidgetsApp's [backButtonDispatcher](https://api.flutter.dev/flutter/widgets/WidgetsApp/backButtonDispatcher.html) is recreated every time if the provided one [is null](https://github.com/flutter/flutter/blob/2.10.0/packages/flutter/lib/src/widgets/app.dart#L448).

Which is causing the following issues
- root / main `Router`'s dependencies [rebuild unnecessary](https://github.com/flutter/flutter/blob/2.10.0/packages/flutter/lib/src/widgets/router.dart#L751)
- nested `Router`'s `backButtonDispatcher` will lose priority since old parent is not wired anymore

Rebuild test outputs
1. initState _// state created_
2. didChangeDependencies _// state created_
3. didChangeDependencies _// Refresh MyApp button pressed or framework caused a rebuild_

```dart
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';

final appKey = GlobalKey();

void main() {
  runApp(const MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  final routerDelegate = MyRouterDelegate();
  late final backButtonDispatcher = RootBackButtonDispatcher();

  @override
  void dispose() {
    routerDelegate.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp.router(
      key: appKey,
      title: 'Router test',
      routerDelegate: routerDelegate,
      backButtonDispatcher: null, // backButtonDispatcher,
      routeInformationParser: const SimpleRouteParser(),
    );
  }
}

class MyRouterDelegate extends RouterDelegate<RouteInformation> with ChangeNotifier {
  @override
  Widget build(BuildContext context) {
    return const SimpleScreen();
  }

  @override
  Future<bool> popRoute() {
    return SynchronousFuture(false);
  }

  @override
  Future<void> setNewRoutePath(RouteInformation configuration) {
    return SynchronousFuture<void>(null);
  }
}

class SimpleScreen extends StatefulWidget {
  const SimpleScreen({Key? key}) : super(key: key);

  @override
  State<SimpleScreen> createState() => _SimpleScreenState();
}

class _SimpleScreenState extends State<SimpleScreen> {
  @override
  void initState() {
    super.initState();
    print('initState');
  }

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    print('didChangeDependencies');
  }

  @override
  Widget build(BuildContext context) {
    Router.of(context);

    return Scaffold(
      appBar: AppBar(title: const Text('SimpleScreen')),
      body: Center(
        child: ElevatedButton(
          // for simplicity
          onPressed: () => appKey.currentState!.setState(() {}),
          child: const Text('Refresh MyApp'),
        ),
      ),
    );
  }
}

class SimpleRouteParser extends RouteInformationParser<RouteInformation> {
  const SimpleRouteParser();

  @override
  Future<RouteInformation> parseRouteInformation(RouteInformation routeInformation) {
    return SynchronousFuture(routeInformation);
  }
}
```

Nested Router asks for priority
_Note: Nested Routers might use this code during `didChangeDependencies` call, however programmers don't often use this state callback and this is risky too if each Tab has it's own Router_
```dart
  @override
  void initState() {
    super.initState();
    _backButtonDispatcher = Router.of(context).backButtonDispatcher!.createChildBackButtonDispatcher();
    _backButtonDispatcher.takePriority();
  }
```

## Proposal
I know [docs](https://api.flutter.dev/flutter/widgets/WidgetsApp/backButtonDispatcher.html) mentions:

> If this is not provided, the widgets app will create a [RootBackButtonDispatcher](https://api.flutter.dev/flutter/widgets/RootBackButtonDispatcher-class.html) by default.

However it shouldn't be recreated every time.

Possible implementation:
```dart
class WidgetsApp extends StatefulWidget {
  final BackButtonDispatcher? backButtonDispatcher;

  WidgetsApp.router({
    Key? key,
    this.backButtonDispatcher,
  }) : super(key: key);

  @override
  _WidgetsAppState createState() => _WidgetsAppState();
}

class _WidgetsAppState extends State<WidgetsApp> {
  late final _defaultBackButtonDispatcher = RootBackButtonDispatcher();

  @override
  Widget build(BuildContext context) {
    Widget? routing;
    if (_usesRouter) {
      routing = Router<Object>(
        backButtonDispatcher: widget.backButtonDispatcher ?? _defaultBackButtonDispatcher,
      );
    }
    // ...
  }
}
```

Developing nested Routers, this issue could cause some headaches if someone assumes `RootbackButtonDispatcher` remain the same during the app's run and already called `deferTo` / `takePriority` methods on `ChildBackButtonDispatcher`.

Note: not only `RouterDelegate.notifyListerners` can ask Router for reporting a new url, someone might use some state management around `MaterialApp.router` and [providing new RouterDelegate instance for it](https://github.com/flutter/flutter/blob/2.10.0/packages/flutter/lib/src/widgets/router.dart#L613) or use `InheritedWidget.of` call inside [`RouterDelegate.build`](https://github.com/flutter/flutter/blob/2.10.0/packages/flutter/lib/src/widgets/router.dart#L586) and in the latter two cases `backButtonDispatcher` will be recreated more often.