面试题答案
一键面试Widget主要生命周期方法
- initState
- 作用:在Widget插入到树中时调用,仅调用一次。用于初始化一些与State相关的状态,比如初始化一些变量,设置监听器等。在StatefulWidget中,这个方法是一个很重要的初始化阶段。
- 示例:
class MyWidget extends StatefulWidget { @override _MyWidgetState createState() => _MyWidgetState(); } class _MyWidgetState extends State<MyWidget> { int _counter = 0; @override void initState() { super.initState(); _counter = 0; } // 省略其他代码 }
- didChangeDependencies
- 作用:当State对象的依赖关系发生变化时调用。例如,当使用InheritedWidget时,如果依赖的InheritedWidget发生变化,这个方法就会被调用。在initState之后也会调用一次。
- 示例:假设依赖一个提供数据的InheritedWidget,当这个InheritedWidget数据变化时更新自身状态。
class MyInheritedWidget extends InheritedWidget { final int data; MyInheritedWidget({required this.data, required Widget child}) : super(child: child); static MyInheritedWidget? of(BuildContext context) { return context.dependOnInheritedWidgetOfExactType<MyInheritedWidget>(); } @override bool updateShouldNotify(MyInheritedWidget oldWidget) { return oldWidget.data != data; } } class DependentWidget extends StatefulWidget { @override _DependentWidgetState createState() => _DependentWidgetState(); } class _DependentWidgetState extends State<DependentWidget> { int _inheritedData = 0; @override void didChangeDependencies() { super.didChangeDependencies(); _inheritedData = MyInheritedWidget.of(context)!.data; } // 省略其他代码 }
- build
- 作用:构建Widget树的核心方法,每次State状态变化时都会调用,返回一个Widget。这个方法应该是无副作用的,即每次调用返回的Widget只依赖于当前的State和配置信息。
- 示例:
class MyWidget extends StatefulWidget { @override _MyWidgetState createState() => _MyWidgetState(); } class _MyWidgetState extends State<MyWidget> { int _counter = 0; @override Widget build(BuildContext context) { return Text('Counter: $_counter'); } }
- dispose
- 作用:当Widget从树中移除时调用,用于释放资源,比如取消定时器、注销监听器等。
- 示例:
class MyWidget extends StatefulWidget { @override _MyWidgetState createState() => _MyWidgetState(); } class _MyWidgetState extends State<MyWidget> { late StreamSubscription _subscription; @override void initState() { super.initState(); _subscription = Stream.periodic(const Duration(seconds: 1)).listen((event) { setState(() { // 更新状态 }); }); } @override void dispose() { _subscription.cancel(); super.dispose(); } // 省略其他代码 }
在包含网络请求的StatefulWidget中合理利用生命周期方法
- 发起网络请求
- initState:通常在initState中发起网络请求是一个不错的选择,因为这个方法只调用一次,适合进行初始化的网络请求操作。
- 示例:
import 'package:http/http.dart' as http; import 'dart:convert'; class NetworkWidget extends StatefulWidget { @override _NetworkWidgetState createState() => _NetworkWidgetState(); } class _NetworkWidgetState extends State<NetworkWidget> { List<dynamic> _data = []; @override void initState() { super.initState(); _fetchData(); } Future<void> _fetchData() async { final response = await http.get(Uri.parse('https://example.com/api/data')); if (response.statusCode == 200) { setState(() { _data = jsonDecode(response.body); }); } } @override Widget build(BuildContext context) { return ListView.builder( itemCount: _data.length, itemBuilder: (context, index) { return ListTile( title: Text(_data[index]['title']), ); }, ); } }
- 处理网络状态改变
- didChangeDependencies:如果网络请求依赖于一些InheritedWidget(比如用于获取网络配置信息等),可以在didChangeDependencies方法中重新发起网络请求。
- 示例:假设InheritedWidget提供网络地址,当地址变化时重新请求数据。
class NetworkConfig extends InheritedWidget { final String apiUrl; NetworkConfig({required this.apiUrl, required Widget child}) : super(child: child); static NetworkConfig? of(BuildContext context) { return context.dependOnInheritedWidgetOfExactType<NetworkConfig>(); } @override bool updateShouldNotify(NetworkConfig oldWidget) { return oldWidget.apiUrl != apiUrl; } } class NetworkWidget extends StatefulWidget { @override _NetworkWidgetState createState() => _NetworkWidgetState(); } class _NetworkWidgetState extends State<NetworkWidget> { List<dynamic> _data = []; @override void didChangeDependencies() { super.didChangeDependencies(); _fetchData(); } Future<void> _fetchData() async { final url = NetworkConfig.of(context)!.apiUrl; final response = await http.get(Uri.parse(url)); if (response.statusCode == 200) { setState(() { _data = jsonDecode(response.body); }); } } @override Widget build(BuildContext context) { return ListView.builder( itemCount: _data.length, itemBuilder: (context, index) { return ListTile( title: Text(_data[index]['title']), ); }, ); } }
- 在build方法中处理网络状态:可以根据网络请求的状态(如loading、success、error)返回不同的Widget。
- 示例:
import 'package:http/http.dart' as http; import 'dart:convert'; class NetworkWidget extends StatefulWidget { @override _NetworkWidgetState createState() => _NetworkWidgetState(); } enum NetworkStatus { loading, success, error } class _NetworkWidgetState extends State<NetworkWidget> { NetworkStatus _status = NetworkStatus.loading; List<dynamic> _data = []; @override void initState() { super.initState(); _fetchData(); } Future<void> _fetchData() async { try { final response = await http.get(Uri.parse('https://example.com/api/data')); if (response.statusCode == 200) { setState(() { _data = jsonDecode(response.body); _status = NetworkStatus.success; }); } else { setState(() { _status = NetworkStatus.error; }); } } catch (e) { setState(() { _status = NetworkStatus.error; }); } } @override Widget build(BuildContext context) { if (_status == NetworkStatus.loading) { return const CircularProgressIndicator(); } else if (_status == NetworkStatus.success) { return ListView.builder( itemCount: _data.length, itemBuilder: (context, index) { return ListTile( title: Text(_data[index]['title']), ); }, ); } else { return const Text('Error occurred while fetching data'); } } }