文章目录
- 学习建议
- 基础层(6 题)
- #1 `Navigator.push` 和 `pop` 做什么? 🔥
- 标准回答
- 面试官可能继续追问
- #2 命名路由怎么用? ⭐
- 标准回答
- 面试官可能继续追问
- #3 `MaterialPageRoute` 是什么? 🔥
- 标准回答
- 面试官可能继续追问
- #4 路由间如何传递参数与返回值? 🔥
- 标准回答
- 面试官可能继续追问
- #5 如何拦截返回键? ⭐
- 标准回答
- 面试官可能继续追问
- #6 底部 Tab 导航常见结构? ⭐
- 标准回答
- 面试官可能继续追问
- 进阶层(6 题)
- #7 Navigator 1.0 的局限? 🔥
- 标准回答
- 面试官可能继续追问
- #8 Navigator 2.0 核心组件? 🔥
- 标准回答
- 面试官可能继续追问
- #9 `go_router` 解决什么问题? 🔥
- 标准回答
- 面试官可能继续追问
- #10 深链(Deep Link)如何处理? ⭐
- 标准回答
- 面试官可能继续追问
- #11 嵌套导航与 `ShellRoute`? ⭐
- 标准回答
- 面试官可能继续追问
- #12 路由与状态如何配合? ⭐
- 标准回答
- 面试官可能继续追问
- 核心层(6 题)
- #13 Navigator 1.0 与 2.0 如何选型? 💡
- 标准回答
- 面试官可能继续追问
- #14 `RouterDelegate` 与状态驱动的关系? 💡
- 标准回答
- 面试官可能继续追问
- #15 Flutter 与 Android Activity 返回栈协同? 🔥
- 标准回答
- 面试官可能继续追问
- #16 Web 与移动端路由差异? ⭐
- 标准回答
- 面试官可能继续追问
- #17 路由鉴权与 redirect 模式? 🔥
- 标准回答
- 面试官可能继续追问
- #18 `Hero` 动画与路由? ⭐
- 标准回答
- 面试官可能继续追问
- 面试策略速查
- 必背知识(🔥)
- 高频追问
- 加分项(💡)
- 容易踩坑
- 完整链路一句通
- 相关推荐
学习建议
| 目标层级 | 建议 |
|---|---|
| 初级 | 掌握基础层 6 题:Navigator.push/pop、命名路由、MaterialPageRoute、路由传参、PopScope拦截返回 |
| 中级 | 通读全文;进阶层能讲清 Navigator 2.0 页面栈、RouterDelegate、go_router与深链、嵌套导航 |
| 高级 | 核心层必答:1.0 vs 2.0 选型与 tradeoff、混合栈与 Android Activity 协同、redirect 鉴权、Web 路由差异 |
基础层(6 题)
#1Navigator.push和pop做什么? 🔥
标准回答
Navigator维护页面栈(Route列表)。push压入新Route并播放过渡动画;pop弹出栈顶返回上一页,可携带result。pushReplacement替换栈顶。根Navigator由MaterialApp/CupertinoApp自动提供。await Navigator.push(context, ...)可异步接收返回结果,功能上类比startActivityForResult。
面试官可能继续追问
Android
startActivity对照?push类似启动新 Activity;pop类似finish();result类似setResult。多个 Navigator 嵌套?
子树可创建独立Navigator,如底部 Tab 每 Tab 各自一套导航栈。
#2 命名路由怎么用? ⭐
标准回答
在MaterialApp的routes表中注册路径→页面映射,通过Navigator.pushNamed(context, '/detail', arguments: id)跳转。onGenerateRoute用于处理动态路径与未知路由。简单应用够用,但复杂场景(深链、Web URL 同步、鉴权重定向)中,命令式命名路由表达能力不足,宜用 Navigator 2.0 或go_router。
面试官可能继续追问
Android
intent-filter深链对照?
命名路由不自动关联 URL;深链解析需 2.0 或go_router配合。arguments类型安全?
运行时类型为Object?,需手动强转;2.0 可用类型化的extra参数。
#3MaterialPageRoute是什么? 🔥
标准回答
实现 Android 风格左右滑入动画的PageRoute子类,builder回调返回目标页 Widget。设置fullscreenDialog: true可变为自下而上弹出。自定义过渡效果用PageRouteBuilder。Route 对象本身负责遮罩、动画、手势返回等行为,页面 Widget 在build中按需构建。
面试官可能继续追问
Android 共享元素过渡?
用Hero组件声明同名 tag 即可实现跨路由飞行动画;复杂共享可用第三方库。透明路由?
自定义PageRoute,设置barrierColor: Colors.transparent等属性。
#4 路由间如何传递参数与返回值? 🔥
标准回答
去程传参:构造函数直接传、ModalRoute.settings.arguments、或 Navigator 2.0 的state.extra。回程返回值:Navigator.pop(context, result)弹出,上一页通过final r = await Navigator.push(...)接收。复杂对象建议传 id 再由状态管理容器查询,避免在路由中传递大对象。深链接参数则通过 query/path 解析。
面试官可能继续追问
Android Bundle 对照?
arguments类似 Bundle;Flutter 无 Parcelable 机制,常用 JSON 或 id 传递。pop 多次怎么处理?
用popUntil或pushNamedAndRemoveUntil清空中间栈,常用于跳转到登录页。
#5 如何拦截返回键? ⭐
标准回答
Flutter 3.12+ 使用PopScope(替代已废弃的WillPopScope):canPop控制是否允许系统返回;onPopInvoked回调处理侧滑或返回键事件,即使canPop: false也会触发。典型场景:表单未保存弹确认对话框、支付流程中禁止返回。Android 预测性返回手势需配合PopScope与主题设置。
面试官可能继续追问
Android
OnBackPressedDispatcher对照?
拦截机制类似;混合页面中原生与 Flutter 可能争抢返回事件,需约定消费优先级。canPop: false后怎么退出?
业务条件满足后手动调用Navigator.pop,或通过 Channel 通知原生finish()。
#6 底部 Tab 导航常见结构? ⭐
标准回答
常见方案:Scaffold+BottomNavigationBar+ 每个 Tab 一个子Navigator,配合IndexedStack保持各 Tab 页面状态。go_router则用StatefulShellRoute为每个分支维护独立导航栈。切换 Tab 时不丢失滚动位置,需搭配AutomaticKeepAliveClientMixin。切忌全应用单栈导致 Tab 间路由互相干扰。
面试官可能继续追问
Android
BottomNavigationView+ 多 Fragment 对照?
每 Tab 独立 back stack,Flutter 对应嵌套Navigator或 shell route。Tab 内再 push 详情页?
在对应 Tab 的子Navigator内 push,不影响其他 Tab 的导航栈。
进阶层(6 题)
#7 Navigator 1.0 的局限? 🔥
标准回答
命令式push/popAPI 使路由状态隐式存在于内部栈中,难以与 URL 栏、系统返回手势、状态恢复保持同步。深链解析、Web 同构、登录重定向等场景需大量样板代码。路由状态不可序列化,调试与测试困难。因此官方推出 Navigator 2.0 声明式模型:pages列表即真相源,系统事件通过改变pages驱动栈重建。
面试官可能继续追问
Android 单 Activity 多 Fragment 像 2.0 吗?
思想相近:回退栈由状态驱动而非命令式操作;Flutter 2.0 用pages显式声明。小项目还要 2.0 吗?
可继续用 1.0;若要 Web 或深链支持,直接用go_router封装更省事。
#8 Navigator 2.0 核心组件? 🔥
标准回答
RouteInformationParser:URI 与RouteInformation互转。RouterDelegate:持有Navigator的pages列表,监听状态变化并通过notifyListeners触发重建。RouteInformationProvider:提供当前路由信息(含平台深链事件)。三者通过MaterialApp.router接入。与 1.0 的关键区别:页面列表变化驱动栈,而非直接调用push/pop。
面试官可能继续追问
手写难度大吗?
样板代码多;生产环境推荐用go_router或auto_route自动生成。pages和 1.0 的routes关系?
2.0 用Page对象列表(如MaterialPage)替代 1.0 隐式栈,状态即文档。
#9go_router解决什么问题? 🔥
标准回答
官方维护的声明式路由库,提供路径模板、query 参数、redirect 重定向、ShellRoute嵌套、深链支持、Web URL 同步。通过GoRouter(routes: [...], redirect: ...)配置,UI 层用context.go/context.push导航。大幅降低手写 Navigator 2.0RouterDelegate的成本,是近 1 年新项目的高频选型。
面试官可能继续追问
Android
Navigation Component对照?
类似 nav graph + deep link 配置;go类似navigate加popUpTo。未登录跳转登录页?
redirect: (context, state) => isLoggedIn ? null : '/login'统一拦截。
#10 深链(Deep Link)如何处理? ⭐
标准回答
移动端:通过uni_links或app_links接收 URI,交给GoRouter或自定义 parser 解析,匹配对应 route,可能先经过redirect拦截。Android 端需在AndroidManifest.xml配置 intent-filter。冷启动与热启动都需处理;参数校验防止非法 path。生产环境推荐 HTTPS App Links 并验证域名所有权。
面试官可能继续追问
Android
intent.data怎么进 Flutter?FlutterActivity设置初始 route,或通过 MethodChannel 传递 URI 给go_router.go。http/https 与自定义 scheme 选择?
生产推荐 HTTPS App Links 验证域名;开发调试可用自定义 scheme。
#11 嵌套导航与ShellRoute? ⭐
标准回答
go_router的ShellRoute/StatefulShellRoute为页面包裹共享外壳(底栏、侧栏),子路由在壳内切换且各自保持独立导航栈,对应多 Tab 场景每 Tab 可有多层详情。通过parentNavigatorKey可将特定路由(如全屏登录页)挂载到根 Navigator,覆盖外壳。
面试官可能继续追问
主界面 + 全屏登录页布局?
登录 route 使用根navigatorKey,不进入 Shell 分支。Tab 切换保留各自栈?
StatefulShellRoute.indexedStack保持各分支页面状态不丢失。
#12 路由与状态如何配合? ⭐
标准回答
路由参数尽量可序列化(如 id),详情页通过Provider/Riverpod按 id 获取数据,而非在路由中传递完整对象。勿在RouteSettings中塞入BuildContext或大对象导致泄漏。登录态变化触发redirect清空非法页面栈。返回结果用pop(result),上一页通过await push接收后刷新对应 provider,避免全局广播。
面试官可能继续追问
返回后如何刷新列表?
await push收到 result 后调用ref.invalidate(listProvider)触发重新请求。路由级状态恢复?
使用RestorationMixin或restorationId配合系统状态恢复 API。
核心层(6 题)
#13 Navigator 1.0 与 2.0 如何选型? 💡
标准回答
1.0:页面少、无 Web 需求、团队熟悉命令式 API。2.0 / go_router:需深链、Web 同构、复杂 redirect 鉴权、可预测回退栈。渐进迁移可让新模块用go_router,旧模块 1.0 共存于不同Navigator。面试时应讲清各自 tradeoff,而非简单否定 1.0。
面试官可能继续追问
存量 Activity 路由如何共存?
原生层仍用 Activity,Flutter 模块内独立GoRouter,边界通过 Channel 协调跳转。学习成本如何评估?
2.0 概念较多(Parser、Delegate);go_router通过声明式路由表大幅降低入门门槛。
#14RouterDelegate与状态驱动的关系? 💡
标准回答
RouterDelegate继承ChangeNotifier,内部pages列表变化时调用notifyListeners,触发MaterialApp.router重建Navigator。系统返回键由popRoute回调修改pages。核心思想是声明式:状态 → pages → UI,而非 UI 层直接命令式操作隐式栈。测试时可直接验证 delegate 的pages序列。
面试官可能继续追问
背压到根路由怎么退出?
pages清空后无法再 pop,通过SystemNavigator.pop()或 Channel 通知原生finish()。多处修改 pages 会冲突吗?
应集中到单一RouterDelegate管理,避免分散setState导致竞态。
#15 Flutter 与 Android Activity 返回栈协同? 🔥
标准回答
混合应用常见形态:单 Activity 承载全量 Flutter或多 Activity 各自嵌入 FlutterFragment。Flutter 内pop到根后继续退出的行为,需通过SystemNavigator.pop()或 MethodChannel 通知原生层finish()。Android 预测性返回手势、多 Fragment 回退场景需明确约定:Flutter 先消费返回事件还是原生先消费。FlutterEngine缓存时路由状态保留在 Dart 侧。
面试官可能继续追问
Flutter 页上再启动原生 Activity?
Channel 调用startActivity,返回后 FlutterRoute仍在引擎栈中未销毁。双返回键体验不一致?
在根路由的PopScope中统一判断,无法继续 pop 时通知原生执行finish()。
#16 Web 与移动端路由差异? ⭐
标准回答
Web 端强依赖地址栏 URL与浏览器前进后退按钮;go_router通过path或hash策略管理 URL。移动端深链无地址栏,但推荐与 Web 端共用相同 path 设计便于同构。Web 需注意:刷新页面时入口 route 必须能独立渲染当前状态。使用url_strategy去除 URL 中#符号需要服务端配合重写。
面试官可能继续追问
只做 App 不考虑 Web?
仍建议用go_router统一 path 规范,后续扩展 Web 成本更低。SEO 与 Flutter Web 的关系?
Android 面试点到即可;首屏渲染模式选择影响 SEO 策略,但非核心考点。
#17 路由鉴权与 redirect 模式? 🔥
标准回答
GoRouter.redirect在每次导航前检查登录态或权限,未授权时返回登录页路径,并可携带returnToquery 参数以便登录后回跳。异步读取 token 时注意避免 redirect 重入死循环与闪屏,可用 loading 壳路由承载过渡态。角色级权限用 guard 函数或分支 redirect 实现。关键:避免在 Widgetbuild中调用context.go造成循环重建。
面试官可能继续追问
原生登录态 Flutter 未感知?
Channel 通知刷新authStateProvider,触发refreshListenable使GoRouter重跑 redirect。token 过期如何踢出?
网络 401 拦截后调用context.go('/login')并清空导航栈,等价于pushReplacement。
#18Hero动画与路由? ⭐
标准回答
两路由间同名Herotag 的 Widget 在 push/pop 时自动生成飞行动画。tag 必须全局唯一;列表项用唯一 id 作为 tag。嵌套 Hero 或过多 Hero 同时飞行会引发性能问题。与MaterialPageRoute默认过渡动画可叠加展示。复杂共享元素场景可自定义flightShuttleBuilder控制飞行过程。
面试官可能继续追问
Android 共享元素 Transition 对照?
设计思想一致;Flutter 声明 tag 即可自动过渡,但要求两端 Widget 子树结构匹配。Hero 报错常见原因?
tag 重复、子树缺少 Material 祖先、列表项未使用唯一 tag 标识。
面试策略速查
| 面试等级 | 建议掌握 |
|---|---|
| 初级 | ★★★☆☆ |
| 中级 | ★★★★☆ |
| 高级 | ★★★★★ |
必背知识(🔥)
push/pop与结果回传、命名路由与onGenerateRoute、Navigator 1.0 局限、2.0 三组件、go_router声明式配置、深链接入处理、混合返回栈协同、redirect 鉴权模式
高频追问
「1.0 和 2.0 区别及选型」「go_router redirect 怎么写」「Tab 怎么保持各自导航栈」「Flutter 根路由如何 finish Activity」「Hero 常见坑」
加分项(💡)
RouterDelegate状态驱动原理、ShellRoute嵌套导航、Web 路由差异与同构、1.0→2.0 渐进迁移策略
容易踩坑
混用多套 Navigator 未指定 key;redirect条件不当导致死循环;深链冷启动未处理参数;混合栈根路由未调用SystemNavigator.pop;arguments强转类型崩溃;build中调用go引发循环重建
完整链路一句通
路由导航一条线:URI 输入或用户操作 → Parser 解析 / redirect 鉴权拦截 → 更新路由状态 →pages列表驱动Navigator重建栈 → 页面通过状态容器按参数取数据 →pop(result)回传上一页;混合栈根路由无路可退时通知原生finish()。
相关推荐
Android 高级工程师面试:Flutter Widget 体系 近1年高频追问 20 题
Android 高级工程师面试:Flutter 布局与绘制 近1年高频追问 20 题