面试题答案
一键面试常见场景一:不当的状态管理 - 静态变量持有Widget引用
- 场景描述:当使用静态变量来持有Widget的引用时,由于静态变量的生命周期与应用程序相同,即使Widget已经从视图树中移除,其引用依然存在,导致无法被垃圾回收,从而引发内存泄漏。 例如:
class MyWidget extends StatefulWidget {
@override
_MyWidgetState createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
static _MyWidgetState? _instance;
@override
void initState() {
super.initState();
_instance = this;
}
@override
Widget build(BuildContext context) {
return Container();
}
}
- 修复思路:避免使用静态变量持有Widget的引用。如果需要在其他地方访问Widget的状态,可以考虑使用更合适的状态管理方案,如InheritedWidget、Provider等。
- 代码实现(使用Provider):
首先添加provider依赖到
pubspec.yaml
:
dependencies:
provider: ^6.0.4
然后修改代码如下:
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class MyWidgetModel extends ChangeNotifier {
// 这里放置需要共享的状态和方法
}
class MyWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (context) => MyWidgetModel(),
child: Scaffold(
body: Container(),
),
);
}
}
在需要访问状态的地方:
class AnotherWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
final model = context.watch<MyWidgetModel>();
return Text('Some text based on model state');
}
}
常见场景二:事件监听未取消
- 场景描述:在Widget中注册了事件监听(如Stream监听、手势监听等),但在Widget销毁时没有取消这些监听,导致监听器依然持有Widget的引用,阻止Widget被垃圾回收。 例如:
class MyWidget extends StatefulWidget {
@override
_MyWidgetState createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
late StreamSubscription<int> _subscription;
@override
void initState() {
super.initState();
_subscription = Stream.periodic(const Duration(seconds: 1)).listen((value) {
setState(() {
// 更新UI
});
});
}
@override
Widget build(BuildContext context) {
return Container();
}
}
- 修复思路:在Widget的
dispose
方法中取消事件监听。 - 代码实现:
class MyWidget extends StatefulWidget {
@override
_MyWidgetState createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
late StreamSubscription<int> _subscription;
@override
void initState() {
super.initState();
_subscription = Stream.periodic(const Duration(seconds: 1)).listen((value) {
setState(() {
// 更新UI
});
});
}
@override
void dispose() {
_subscription.cancel();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Container();
}
}
常见场景三:动画未停止
- 场景描述:在Widget中启动了动画(如
AnimationController
),但在Widget销毁时没有停止动画,导致动画控制器依然持有Widget的引用,造成内存泄漏。 例如:
class MyWidget extends StatefulWidget {
@override
_MyWidgetState createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
late AnimationController _controller;
@override
void initState() {
super.initState();
_controller = AnimationController(
vsync: this,
duration: const Duration(seconds: 2),
)..repeat();
}
@override
Widget build(BuildContext context) {
return Container();
}
}
- 修复思路:在Widget的
dispose
方法中停止动画并释放动画控制器。 - 代码实现:
class MyWidget extends StatefulWidget {
@override
_MyWidgetState createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
late AnimationController _controller;
@override
void initState() {
super.initState();
_controller = AnimationController(
vsync: this,
duration: const Duration(seconds: 2),
)..repeat();
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Container();
}
}