MaterialApp에서 routes를 설정하여 Navigation을 잘 이용하고 있었다. Provider와 같이 이용하고 있었는데 회원가입할 때 정보를 여러 페이지로 나누어서 입력을 받아 회원가입을 진행하는 것으로 되었다. sigup_first_page와 signup_second_page가 있을 때 sigup_first_page에서 signup_provider를 생성하여 사용하니 signup_first_page에서 Navigaion으로 second페이지로 이동 후 해당 provider를 사용하려고 하니 아래와 같은 에러가 발생하였다.

해당 페이지의 BuildContext에서 Provider를 찾을 수 없다는 내용이다. Flutter inspector를 통해서 에러의 원인을 찾아보자

First 페이지에서 pushNamed로 Second 페이지로 이동을 했다고해서 Widget tree 상에서 부모-자식 관계가 아니라 같은 레벨의 Widget이라는 것을 확인할 수 있다. 그렇기 때문에 First페이지에서 생성한 Provider를 Second 페이지에서 사용할 수 없었다.
MyApp 이나 MaterialApp 기준으로 Provider를 생성을 하면 first 페이지에서도 second 페이지에서도 사용할 수 있지만 signup과 관련없는 페이지에서도 접근할 수 있게 된다. Nested Navigator을 알게 되어 이것을 적용하여 해결해보려고 한다. Nested Navigator은 Multi Navigator 라고 이해하면 된다.
디렉토리 구조는 아래와 같이 했다.

app.dart (top level route)
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
initialRoute: '/',
routes: {
'/' : (BuildContext context) => HomePage(),
'/signup' : (BuildContext context) => SignupPage(),
},
);
}
}
home_page
class HomePage extends StatelessWidget {
const HomePage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('home'),
),
body: Center(
child: ElevatedButton(
onPressed: () {
Navigator.of(context).pushNamed('/signup');
},
child: const Text(
'sign up',
style: TextStyle(fontSize: 20),
),
),
),
);
}
}
signup_provider
class SignupProvider extends ChangeNotifier {
final navigatorKey = GlobalKey<NavigatorState>();
int _count = 0;
int get count => _count;
set count(int value) {
_count = value;
notifyListeners();
}
}
signup_page
class SignupPage extends StatelessWidget {
const SignupPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (context) => SignupProvider(),
child: Builder(
builder: (context) {
return Navigator(
key: context.read<SignupProvider>().navigatorKey,
initialRoute: 'first',
onGenerateRoute: (RouteSettings settings){
late Widget page;
switch(settings.name){
case 'first' :
page = SignupFirstDepthPage();
break;
case 'second' :
page = SignupSecondDepthPage();
break;
default:
throw Exception('Invalid route: ${settings.name}');
}
return MaterialPageRoute(
builder: (context) {
return page;
},
settings: settings,
);
},
);
}
),
);
}
}
signup_first_depth_page
class SignupFirstDepthPage extends StatelessWidget {
const SignupFirstDepthPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: ElevatedButton(onPressed: (){
Navigator.of(context).pushNamed('second');
}, child: const Text('다음', style: TextStyle(fontSize: 20),),),
),
);
}
}
signup_second_depth_page
class SignupSecondDepthPage extends StatelessWidget {
const SignupSecondDepthPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Text('sign up second page ${context.watch<SignupProvider>().count}'),
),
);
}
}

하드웨어 back button으로 뒤로 가면 second 페이지에서 first페이지로 가는게 아니라 HomePage로 이동한다. 그래서 WillPopScope 위젯을 이용해서 제어해야 할 것 같다.