面试题答案
一键面试页面缓存策略
- 使用
AutomaticKeepAliveClientMixin
:对于需要复用且保持状态的页面,让页面的State
类混入AutomaticKeepAliveClientMixin
。例如:
class MyReusablePageState extends State<MyReusablePage> with AutomaticKeepAliveClientMixin {
@override
bool get wantKeepAlive => true;
@override
Widget build(BuildContext context) {
super.build(context);
// 页面构建逻辑
return Container();
}
}
这样即使页面被移出屏幕,其状态也会被保留,下次再进入时无需重新构建。
2. 自定义缓存机制:可以创建一个缓存池,使用 Map
来存储已创建的页面实例。例如:
Map<String, Widget> pageCache = {};
Widget getCachedPage(String routeName) {
return pageCache[routeName];
}
void cachePage(String routeName, Widget page) {
pageCache[routeName] = page;
}
当页面需要被复用时,先从缓存池中查找,如果存在则直接使用,避免重复创建。
路由表设计
- 集中式路由表:创建一个单独的类来管理所有路由,这样便于维护和查找。例如:
class AppRoutes {
static const String home = '/home';
static const String reusablePage = '/reusablePage';
static Map<String, WidgetBuilder> routes = {
home: (context) => HomePage(),
reusablePage: (context) => ReusablePage(),
};
}
在 MaterialApp
中使用这个路由表:
MaterialApp(
initialRoute: AppRoutes.home,
routes: AppRoutes.routes,
);
- 命名路由与参数传递:使用命名路由时,可以方便地传递参数。例如:
Navigator.pushNamed(context, AppRoutes.reusablePage, arguments: {'key': 'value'});
在目标页面中获取参数:
class ReusablePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
final args = ModalRoute.of(context)!.settings.arguments as Map<String, dynamic>;
return Container();
}
}
异常情况下的页面恢复
- 保存页面状态:在页面状态发生变化时,将关键状态信息保存到持久化存储中,如
SharedPreferences
或数据库。例如,对于一个有输入文本的页面:
class InputPageState extends State<InputPage> {
String inputText = '';
@override
void initState() {
super.initState();
_loadInputText();
}
Future<void> _loadInputText() async {
final prefs = await SharedPreferences.getInstance();
setState(() {
inputText = prefs.getString('inputText')?? '';
});
}
@override
void dispose() {
_saveInputText();
super.dispose();
}
Future<void> _saveInputText() async {
final prefs = await SharedPreferences.getInstance();
prefs.setString('inputText', inputText);
}
@override
Widget build(BuildContext context) {
return TextField(
onChanged: (value) {
setState(() {
inputText = value;
});
},
controller: TextEditingController(text: inputText),
);
}
}
- 恢复页面栈:在应用启动或页面被系统回收后重新创建时,根据保存的页面历史记录(可以存储在持久化存储中)来恢复页面栈。例如,记录当前所在页面的路由名称和传递的参数,然后使用
Navigator.pushNamed
等方法重新构建页面栈。
确保页面状态的正确传递和管理
- 使用
InheritedWidget
或Provider
:对于需要在多个页面间共享的状态,使用InheritedWidget
或Provider
。例如,使用Provider
管理用户登录状态:
class UserProvider with ChangeNotifier {
bool isLoggedIn = false;
void login() {
isLoggedIn = true;
notifyListeners();
}
void logout() {
isLoggedIn = false;
notifyListeners();
}
}
在 main.dart
中提供 UserProvider
:
MultiProvider(
providers: [
ChangeNotifierProvider(create: (context) => UserProvider()),
],
child: MyApp(),
);
在页面中使用 UserProvider
:
class LoginPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
final userProvider = Provider.of<UserProvider>(context);
return ElevatedButton(
onPressed: () {
userProvider.login();
},
child: Text('Login'),
);
}
}
- 页面间状态传递:对于父子页面间的状态传递,可以通过构造函数传递。例如:
class ParentPage extends StatelessWidget {
String parentData = 'Initial data';
@override
Widget build(BuildContext context) {
return ChildPage(data: parentData);
}
}
class ChildPage extends StatelessWidget {
final String data;
ChildPage({required this.data});
@override
Widget build(BuildContext context) {
return Text(data);
}
}
如果是兄弟页面间传递状态,可以通过共同的父级页面或使用事件总线等方式。