Flutter didChangeDependencies和initState之间有什么区别?
我不熟悉flifter,当我想在InitState中调用我的上下文时,它会抛出一个错误: 关于Flutter didChangeDependencies和initState之间有什么区别?,flutter,dart,Flutter,Dart,我不熟悉flifter,当我想在InitState中调用我的上下文时,它会抛出一个错误: 关于 BuildContext.inheritFromWidgetOfExactType 但是我使用了didChangeDependencies,它工作正常 现在我有两个问题: 1-为什么在initState中调用我们的上下文不起作用,但在从didChangeDependencies调用时却起作用? (因为正如我在官方文档中读到的那样,这个方法也会在[initState]之后立即调用, 这两个函数都将在生成
BuildContext.inheritFromWidgetOfExactType
但是我使用了didChangeDependencies,它工作正常
现在我有两个问题:
1-为什么在initState中调用我们的上下文不起作用,但在从didChangeDependencies调用时却起作用?
(因为正如我在官方文档中读到的那样,这个方法也会在[initState]
之后立即调用,
这两个函数都将在生成方法之前调用。)
2-为什么我们可以访问构建方法之外的上下文(因为在那里我们有build(BuildContext)
,我们可以使用上下文,但在didChangeDependencies中我们没有类似于didChangeDependencies(BuildContext)
,所以我们可以从哪里调用上下文来使用它)
无法从此方法中使用BuildContext.inheritFromWidgetOfExactType
。但是,此方法之后将立即调用didChangeDependencies
,并且可以在那里使用BuildContext.inheritFromWidgetOfExactType
因此,您需要在didChangeDependencies
中使用BuildContext.inheritFromWidgetOfExactType
上下文。这就是为什么您可以访问构建方法外部的上下文李>
关于build(BuildContext)
,build
方法从父窗口小部件接受context
。这意味着此参数BuildContext
不是当前小部件的上下文,而是其父部件的上下文。答案是
不应从小部件构造函数或State.initState方法调用此方法,因为如果继承的值发生更改,则不会再次调用这些方法。若要确保小部件在继承的值更改时正确更新自身,请仅从构建方法、布局和绘制回调或State.didChangeDependencies调用它(直接或间接)
从状态加载其依赖项的那一刻起,状态的上下文就对我们可用
在调用build时,上下文对我们可用,并作为参数传递
现在继续,
initstate在状态加载其依赖项之前被调用,因此没有上下文可用,如果在initstate中使用上下文,则会出现错误。
然而,didChangeDependencies仅在状态加载其依赖项后几分钟被调用,此时上下文可用,因此您可以在这里使用上下文
但是,在调用build之前会调用这两个函数。
唯一的区别是,一个在状态加载其依赖项之前调用,另一个在状态加载其依赖项之后几分钟调用
我发现initState
和didChangeDependencies
之间存在显著差异:
initState
对于小部件只调用一次
didChangeDependencies
可以在每个小部件生命周期中调用多次(在我的例子中,它是在键盘出现/消失时调用的)
当此状态对象的依赖项更改时调用
例如,如果上一次对构建的调用引用了一个后来更改的继承的widget,则框架将调用此方法来通知此对象该更改
此方法也会在initState之后立即调用。可以安全地从此方法调用BuildContext.dependonheritedWidgeToFexactType
事实上,子类很少重写此方法,因为框架总是在依赖项更改后调用build。有些子类确实会重写此方法,因为当它们的依赖项发生变化时,它们需要执行一些昂贵的工作(例如,网络获取),而这些工作对于每个构建来说都太昂贵了。initState()
在树中插入新小部件时调用。
框架将为每个[State]对象调用此方法一次
它创造了。这将被调用一次,因此执行只需要执行一次的工作,但请记住这里不能使用上下文
,因为小部件状态仅加载initState()
工作已完成
语法:
@override
void initState() {
debugPrint('initState()');
super.initState();
}
class ParentWidget extends StatefulWidget {
ParentWidget({Key key, this.title}) : super(key: key);
final String title;
@override
_ParentWidgetState createState() => _ParentWidgetState();
}
class _ParentWidgetState extends State<ParentWidget> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Life Cycle'),
),
body: Provider.value(
value: _counter,
updateShouldNotify: (oldValue, newValue) => true,
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'Press Fab button to increase counter:',
),
ChildWidget()
],
),
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
class ChildWidget extends StatefulWidget {
@override
_ChildWidgetState createState() => _ChildWidgetState();
}
class _ChildWidgetState extends State<ChildWidget> {
int _counter = 0;
@override
void initState() {
print('initState(), counter = $_counter');
super.initState();
}
@override
void didChangeDependencies() {
_counter = Provider.of<int>(context);
print('didChangeDependencies(), counter = $_counter');
super.didChangeDependencies();
}
@override
Widget build(BuildContext context) {
print('build(), counter = $_counter');
return Text(
'$_counter',
);
}
}
I/flutter ( 3779): didChangeDependencies(), counter = 1
I/flutter ( 3779): build(), counter = 1
didChangeDependencies()
当此[State]对象的依赖项更改时调用
所以,确切地说,它是如何被调用的?根据上面的定义,它看起来像是在状态改变后被调用的,但是我们如何知道状态改变了呢
示例:
@override
void initState() {
debugPrint('initState()');
super.initState();
}
class ParentWidget extends StatefulWidget {
ParentWidget({Key key, this.title}) : super(key: key);
final String title;
@override
_ParentWidgetState createState() => _ParentWidgetState();
}
class _ParentWidgetState extends State<ParentWidget> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Life Cycle'),
),
body: Provider.value(
value: _counter,
updateShouldNotify: (oldValue, newValue) => true,
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'Press Fab button to increase counter:',
),
ChildWidget()
],
),
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
class ChildWidget extends StatefulWidget {
@override
_ChildWidgetState createState() => _ChildWidgetState();
}
class _ChildWidgetState extends State<ChildWidget> {
int _counter = 0;
@override
void initState() {
print('initState(), counter = $_counter');
super.initState();
}
@override
void didChangeDependencies() {
_counter = Provider.of<int>(context);
print('didChangeDependencies(), counter = $_counter');
super.didChangeDependencies();
}
@override
Widget build(BuildContext context) {
print('build(), counter = $_counter');
return Text(
'$_counter',
);
}
}
I/flutter ( 3779): didChangeDependencies(), counter = 1
I/flutter ( 3779): build(), counter = 1
下面的示例使用提供者
状态管理机制从父窗口小部件更新子窗口小部件。Provider
有一个名为updateShouldNotify
的属性,它决定是否更改状态。如果它返回true
,则在ChildWidget
类中只调用didChangeDependencies
updateShouldNotify在内部默认情况下返回true,因为它知道状态已更改那么为什么我们需要更新houldnotify?这是必要的,因为如果有人想在特定条件下更新状态,
例如:如果UI要求只显示偶数值,那么我们可以添加如下条件
updateShouldNotify: (oldValue, newValue) => newValue % 2 == 0,
代码片段:
@override
void initState() {
debugPrint('initState()');
super.initState();
}
class ParentWidget extends StatefulWidget {
ParentWidget({Key key, this.title}) : super(key: key);
final String title;
@override
_ParentWidgetState createState() => _ParentWidgetState();
}
class _ParentWidgetState extends State<ParentWidget> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Life Cycle'),
),
body: Provider.value(
value: _counter,
updateShouldNotify: (oldValue, newValue) => true,
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'Press Fab button to increase counter:',
),
ChildWidget()
],
),
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
class ChildWidget extends StatefulWidget {
@override
_ChildWidgetState createState() => _ChildWidgetState();
}
class _ChildWidgetState extends State<ChildWidget> {
int _counter = 0;
@override
void initState() {
print('initState(), counter = $_counter');
super.initState();
}
@override
void didChangeDependencies() {
_counter = Provider.of<int>(context);
print('didChangeDependencies(), counter = $_counter');
super.didChangeDependencies();
}
@override
Widget build(BuildContext context) {
print('build(), counter = $_counter');
return Text(
'$_counter',
);
}
}
I/flutter ( 3779): didChangeDependencies(), counter = 1
I/flutter ( 3779): build(), counter = 1
详细说明:
@override
void initState() {
debugPrint('initState()');
super.initState();
}
class ParentWidget extends StatefulWidget {
ParentWidget({Key key, this.title}) : super(key: key);
final String title;
@override
_ParentWidgetState createState() => _ParentWidgetState();
}
class _ParentWidgetState extends State<ParentWidget> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Life Cycle'),
),
body: Provider.value(
value: _counter,
updateShouldNotify: (oldValue, newValue) => true,
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'Press Fab button to increase counter:',
),
ChildWidget()
],
),
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
class ChildWidget extends StatefulWidget {
@override
_ChildWidgetState createState() => _ChildWidgetState();
}
class _ChildWidgetState extends State<ChildWidget> {
int _counter = 0;
@override
void initState() {
print('initState(), counter = $_counter');
super.initState();
}
@override
void didChangeDependencies() {
_counter = Provider.of<int>(context);
print('didChangeDependencies(), counter = $_counter');
super.didChangeDependencies();
}
@override
Widget build(BuildContext context) {
print('build(), counter = $_counter');
return Text(
'$_counter',
);
}
}
I/flutter ( 3779): didChangeDependencies(), counter = 1
I/flutter ( 3779): build(), counter = 1
您仍然可以在initState()方法中使用context,它的hack-buts可以工作,您所需要做的就是延迟您需要执行的任何包含context的操作,如下所示:
@override
void initState() {
Future.delayed(Duration.zero).then((_) {
// you code with context here
});
super.initState();
}
这是一个补充答案,显示了OP所描述的内容
StatefulWidget
的State
类具有context
属性。此生成上下文首先在didChangeDependencies
中可用。试图