Sate獲取StatefulWidget參數(shù)值常見的兩種方式
1铡原、StatefulWidget傳參給State庆尘,在Sate直接使用StatefulWidget傳來的參數(shù)值,如下:
class TestStatefulWidget extends StatefulWidget {
//參數(shù)
final String _xxx;
TestStatefulWidget(this._xxx);
@override
_TestStatefulWidgetState createState() => _TestStatefulWidgetState(this._xxx);
}
class _TestStatefulWidgetState extends State<TestStatefulWidget> {
final _xxx;
_TestStatefulWidgetState(this._xxx);
@override
Widget build(BuildContext context) {
return Container(
child: Text(_xxx), //直接使用StatefulWidget傳來的參數(shù)值
);
}
}
2、StatefulWidget不傳參給State,在Sate通過widget.xxx獲取StatefulWidget的參數(shù)值拐云,如下:
class TestStatefulWidget extends StatefulWidget {
//參數(shù)
final String _xxx;
TestStatefulWidget(this._xxx);
@override
_TestStatefulWidgetState createState() => _TestStatefulWidgetState();
}
class _TestStatefulWidgetState extends State<TestStatefulWidget> {
_TestStatefulWidgetState();
@override
Widget build(BuildContext context) {
return Container(
child: Text(widget._xxx), //通過widget獲取StatefulWidget參數(shù)值
);
}
}
Sate通過widget.xxx獲取StatefulWidget參數(shù)值之坑
上面兩種獲取參值方式的差別在于StatefulWidget有沒有將參數(shù)直接傳給State,Sate是否通過widget.xxx獲取StatefulWidget參數(shù)值近她;
下面通過實例來演示這兩種獲取參數(shù)值的差別慨丐,如下:
class StatefulWidgetParamPage extends StatefulWidget {
final String title;
StatefulWidgetParamPage({Key key, this.title}) : super(key: key);
@override
_StatefulWidgetParamPageState createState() =>
_StatefulWidgetParamPageState();
}
class _StatefulWidgetParamPageState extends State<StatefulWidgetParamPage> {
int i;
@override
void initState() {
super.initState();
i = 0;
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Container(
alignment: Alignment.center,
width: double.infinity,
height: double.infinity,
child: Column(
children: <Widget>[
TestWidgetA(
TestModel(
'WidgetA參數(shù):',
),
i.toString()),
TestWidgetB(TestModel('WidgetB參數(shù):'), i.toString()),
RaisedButton(
onPressed: () {
i++;
setState(() {});
},
child: Text('值增加刷新')),
RaisedButton(
onPressed: () {
i++;
},
child: Text('值增加不刷新')),
RaisedButton(
onPressed: () {
setState(() {});
},
child: Text('只刷新')),
],
)),
);
}
}
class TestModel {
String title;
dynamic value;
TestModel(
this.title,
) {
var r = new Random();
value = r.nextInt(1000); //用于區(qū)分對象是否有重新創(chuàng)建,對象重新創(chuàng)建泄私,值會變化
}
@override
String toString() {
return '$title 自定義對象${value ?? ''}';
}
}
class TestWidgetA extends StatefulWidget {
final TestModel model;
final String value;
TestWidgetA(this.model, this.value);
@override
_TestWidgetAState createState() => _TestWidgetAState();
}
class _TestWidgetAState extends State<TestWidgetA> {
@override
Widget build(BuildContext context) {
return GestureDetector(
child: Container(
alignment: Alignment.center,
child: Text(
'${widget?.model?.toString()} change value=${widget?.value}\ncontext=$context\n'), //展示傳參數(shù)據(jù) 值隨刷新變
),
onTap: () {
print(
'${widget?.model?.toString()} change value=${widget?.value}\ncontext=$context\n'); //值不變,刷新后widget重新創(chuàng)建,值才變
/*setState(() {//內部刷新
});*/
},
);
}
}
class TestWidgetB extends StatefulWidget {
final TestModel model;
final String value;
TestWidgetB(this.model, this.value);
@override
_TestWidgetBState createState() => _TestWidgetBState(this.model, this.value);
}
class _TestWidgetBState extends State<TestWidgetB> {
final TestModel model;
final String value;
_TestWidgetBState(this.model, this.value);
@override
Widget build(BuildContext context) {
return GestureDetector(
child: Container(
alignment: Alignment.center,
child: Text(
'${model?.toString()} change value=$value\ncontext=$context\n'), //展示傳參數(shù)據(jù) 值不隨刷新變
),
onTap: () {
print(
'${model?.toString()} change value=$value\ncontext=$context\n'); //值不隨刷新變
/*setState(() {//內部刷新
});*/
},
);
}
}
上面代碼比較多晌端,可以先不看捅暴,先看下面的實例效果或自行跑demo,不懂再來看代碼和代碼說明
代碼說明:
- 上面代碼通過TestWidgetA咧纠、TestWidgetB兩個StatefulWidget來展示Sate獲取StatefulWidget參數(shù)值不同方式帶來的不同效果蓬痒;
- TestWidgetA:StatefulWidget不傳參給State,在Sate通過widget.xxx獲取StatefulWidget的參數(shù)值漆羔;
- TestWidgetB:StatefulWidget傳參給State梧奢,在Sate直接使用StatefulWidget傳來的參數(shù)值;
- TestWidgetA演痒、TestWidgetB參數(shù)值有:自定義對象TestModel亲轨,外部計數(shù)值;
- TestWidgetA鸟顺、TestWidgetB除State獲取StatefulWidget參數(shù)值方式不一樣惦蚊,其它都一樣,同時展示StatefulWidget參數(shù)值:自定義對象讯嫂、外部計數(shù)參數(shù)值蹦锋;
- 自定義對象TestModel:
1、自定義對象TestModel欧芽,在構造方法初始化里用隨機數(shù)賦值莉掂,可通過觀察隨機數(shù)值有沒有變化來判斷自定義對象有沒有重新創(chuàng)建;
2千扔、自定義對象TestModel作為TestWidgetA憎妙、TestWidgetB兩個StatefulWidget的參數(shù),并且自定義對象TestModel是直接實例化傳給widgetTestWidgetA昏鹃、TestWidgetB作為參數(shù)的; - 外部計數(shù)值尚氛,用于觀察外部值變化 ,Sate獲取StatefulWidget參數(shù)值是否會跟著變化洞渤;
- TestWidgetA阅嘶、TestWidgetB展示各自的context是為了說明各自的State沒重新創(chuàng)建,上面例子不會引起TestWidgetA和TestWidgetB各自Sate的重新創(chuàng)建载迄;
- 三個按鍵功能分別是: 外部計數(shù)值增加并刷新界面讯柔、 外部計數(shù)值增加不刷新界面、只刷新界面护昧;
- 還有TestWidgetA魂迄、TestWidgetB本身的點擊事件,點擊在log打印惋耙,可實時看到傳參值捣炬,分為內部刷新和內部不刷新兩種熊昌;
外部計數(shù)值增加增加并刷新界面效果:
效果說明:
- 界面刷新時,每刷新一次湿酸,TestWidgetA(Sate 通過widget.xxx獲取StatefulWidget參數(shù)值)的自定義對象參數(shù)值發(fā)生了重新創(chuàng)建婿屹,同時外面?zhèn)鱽淼膮?shù)值隨著外面值的變化而變化;
- 界面刷新時推溃,TestWidgetB(Sate 沒有通過widget.xxx獲取StatefulWidget參數(shù)值)的自定義對象參數(shù)值沒有發(fā)生重新創(chuàng)建昂利,外面?zhèn)鱽淼膮?shù)值也沒有隨著外面值的變化而變化,也就是TestWidgetB參數(shù)值沒有發(fā)生變化铁坎;
外部計數(shù)值增加不刷新界面效果:
效果說明:
- 只是值增加時蜂奸,TestWidgetA、TestWidgetB的自定義對象參數(shù)沒有發(fā)生重新創(chuàng)建硬萍,外面?zhèn)鱽淼膮?shù)值也沒有隨著外面值的變化而變化扩所;
- 再刷新時,TestWidgetA(Sate 通過widget.xxx獲取StatefulWidget參數(shù)值)的自定義對象參數(shù)值馬上發(fā)生了重新創(chuàng)建襟铭,同時外面?zhèn)鱽淼膮?shù)值隨著外面值的變化而變化碌奉;TestWidgetB(Sate 沒有通過widget.xxx獲取StatefulWidget參數(shù)值)參數(shù)值沒有發(fā)生變化;
只刷新界面效果:
效果說明:
- 只刷新界面時寒砖,TestWidgetA(Sate 通過widget.xxx獲取StatefulWidget參數(shù)值)的自定義對象參數(shù)值發(fā)生了重新創(chuàng)建赐劣;
- TestWidgetB(Sate 沒有通過widget.xxx獲取StatefulWidget參數(shù)值)參數(shù)值不會發(fā)生變化;
不刷新哩都,連續(xù)點擊獲取實時參數(shù)值效果:
效果說明:
- 不刷新魁兼,實時獲取TestWidgetA、TestWidgetB參數(shù)值漠嵌,TestWidgetA咐汞、TestWidgetB參數(shù)值都不會發(fā)生變化;
內部刷新儒鹿,連續(xù)點擊獲取實時參數(shù)值效果:
效果說明:
- 內部刷新,實時獲取TestWidgetA约炎、TestWidgetB參數(shù)植阴,TestWidgetA、TestWidgetB參數(shù)都不會發(fā)生變化圾浅;
總結
StatefulWidget傳參給State掠手,在Sate直接使用StatefulWidget傳來的參數(shù)值:
- 無論StatefulWidget內部刷新界面、外部刷新界面狸捕,外部參數(shù)值變化喷鸽,在Sate直接獲取StatefulWidget的參數(shù)值都不會改變;
StatefulWidget不傳參給State灸拍,在Sate通過widget.xxx獲取StatefulWidget傳來的參數(shù)值:
- StatefulWidget內部刷新界面做祝,外面值變化時砾省,在Sate通過widget.xxx獲取參數(shù)值不會變化;
- 外部界面刷新混槐,在Sate通過widget.xxx獲取StatefulWidget的參數(shù)值隨外面值變化而變化纯蛾;如果自定義對象直接實例化作為StatefulWidget參數(shù),自定義對象參數(shù)值會隨刷新而發(fā)生重新創(chuàng)建纵隔,這點需要重點留意,有可能界面刷新炮姨,自定義對象定義里的值就變成初始化的值了捌刮。
原因分析
1、外部界面刷新:
- 外部界面刷新時舒岸,Sate里的widget發(fā)生了重新創(chuàng)建
對于StatefulWidget绅作,Sate和Widget是分離的,widget是一個臨時配置對象蛾派,外部界面刷新時俄认,Sate里的widget會發(fā)生重新創(chuàng)建初始化,widget重新創(chuàng)建初始化洪乍,必會重新執(zhí)行StatefulWidget的構造方法眯杏,StatefulWidget的構造方法重新構建,StatefulWidget的構造方法里的參數(shù)必會跟著重新初始化傳入壳澳,所以在Sate通過widget.xxx獲取StatefulWidget的參數(shù)值隨外部刷新而變化岂贩; - 外部界面刷新時,Sate沒有發(fā)生重新創(chuàng)建
由于外部界面刷新時巷波,Sate沒有發(fā)生重新創(chuàng)建萎津,StatefulWidget將參數(shù)傳給State,也就是拷貝了一份參數(shù)值給Sate抹镊,所以即使widget發(fā)生了重新創(chuàng)建锉屈,Sate獲取的到StatefulWidget的參數(shù)值還是最開始StatefulWidget拷貝的參數(shù)值,沒有變化垮耳;
2颈渊、StatefulWidget內部刷新:
- StatefulWidget內部刷新時,Sate和widget都沒有發(fā)生重新創(chuàng)建氨菇,所以無論Sate是否通過widget.xxx獲取StatefulWidget傳來的參數(shù)值儡炼,都沒有變化;
溫馨提示:源碼里大多都是通過widget.xxx來獲取StatefulWidget參數(shù)值查蓉,所以并不是說widget.xxx不可取乌询,這兩種方式各有優(yōu)劣勢,用哪一種根據(jù)自己的業(yè)務進行取舍豌研,文章主要是為了說明Sate 通過widget.xxx 獲取StatefulWidget參數(shù)值需要注意參數(shù)值可能隨外部環(huán)境變化而會變化妹田。