当前位置:网站首页>Flutter tips: optimizing the buildcontext you use
Flutter tips: optimizing the buildcontext you use
2022-07-25 19:24:00 【Love cat de Xiaoguo】
Flutter Inside BuildContext I'm sure everyone will be familiar with , Although it's called Context, But it's actually Element The abstract object of , And in the Flutter in , It mainly comes from ComponentElement .
About ComponentElement Let me give you a brief introduction , stay Flutter According to the Element It can be simply summarized into two categories :
RenderObjectElement: HaveRenderObject, Have the ability of layout and drawing ElementComponentElement: No,RenderObject, That we use a lotStatelessWidgetandStatefulWidgetCorresponding toStatelessElementandStatefulElementIs its subclass .
So in general , We are build Methods or State What we got in BuildContext In fact, that is ComponentElement .
That use BuildContext Are there any problems that need attention ?
First, the following code is shown , In this example, when the user clicks FloatingActionButton When , There is one in the code 2 Second delay , Then call pop Exit the current page .
class _ControllerDemoPageState extends State<ControllerDemoPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
floatingActionButton: FloatingActionButton(
onPressed: () async {
await Future.delayed(Duration(seconds: 2));
Navigator.of(context).pop();
},
),
);
}
}
Under normal circumstances, there will be no problem , But when the user clicks FloatingActionButton after , Click again immediately AppBar Return to exit the application , At this time, the following error prompt will appear .

You can see at this time log say ,Widget Corresponding Element It's gone , Because in Navigator.of(context) When called ,context Corresponding Element It has been destroyed with our withdrawal .
In general, it is also very simple to deal with this problem , That is to increase mounted Judge , adopt mounted Judgment can avoid the above mistakes .
class _ControllerDemoPageState extends State<ControllerDemoPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
floatingActionButton: FloatingActionButton(
onPressed: () async {
await Future.delayed(Duration(seconds: 2));
if (!mounted) return;
Navigator.of(context).pop();
},
),
);
}
}
In the code above mounted The identification bit comes from State , because State Is attached to Element establish , So it can sense Element Life cycle of , for example mounted It is judgement. _element != null; .

So here we have gained a little skill : Use BuildContext when , When necessary, we need to pass mounted To ensure its effectiveness .
So just use mounted You can satisfy context Have you met the requirements of optimization ?
As shown in the following code , In this case :
- We added a list , Use
builderstructure Item - Each list has a click event
- When we click on the list, we simulate the network request , Suppose the network is not very good , So delay a 5 second
- Then we slide the list and click Item Slide out of the screen and not visible
class _ControllerDemoPageState extends State<ControllerDemoPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: ListView.builder(
itemBuilder: (context, index) {
return ListItem();
},
itemCount: 30,
),
);
}
}
class ListItem extends StatefulWidget {
const ListItem({Key? key}) : super(key: key);
@override
State<ListItem> createState() => _ListItemState();
}
class _ListItemState extends State<ListItem> {
@override
Widget build(BuildContext context) {
return ListTile(
title: Container(
height: 160,
color: Colors.amber,
),
onTap: () async {
await Future.delayed(Duration(seconds: 5));
if(!mounted) return;
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text("Tip")));
},
);
}
}
Because in 5 In seconds ,Item Was drawn out of the screen , So the corresponding Elment In fact, he was released , Thus, due to mounted Judge ,SnackBar Will not be ejected .
Suppose you need to show the results of click data reporting during development , That is to say Item It needs to pop up after being released , At this time, how to deal with ?
We know that whether it's ScaffoldMessenger.of(context) still Navigator.of(context) , Its essence is still through context Go up and find the corresponding InheritedWidget Generic , So we can get it in advance .
therefore , As shown in the following code , stay Future.delayed We passed before ScaffoldMessenger.of(context); Get sm object , After that, even if you exit the current list page directly ,5 Seconds later SnackBar Can also pop up normally .
class _ListItemState extends State<ListItem> {
@override
Widget build(BuildContext context) {
return ListTile(
title: Container(
height: 160,
color: Colors.amber,
),
onTap: () async {
var sm = ScaffoldMessenger.of(context);
await Future.delayed(Duration(seconds: 5));
sm.showSnackBar(SnackBar(content: Text("Tip")));
},
);
}
}
Why is the page destroyed , however SnackBar It can pop up normally ?
Because it passes of(context); Acquired ScaffoldMessenger Exist MaterialApp in , So even if the page is destroyed, it doesn't affect SnackBar Implementation .
But if we modify the example , As shown in the following code , stay Scaffold There is one more nested above ScaffoldMessenger , At this time Item Pass through ScaffoldMessenger.of(context) What you get will be under the current page ScaffoldMessenger .
class _ControllerDemoPageState extends State<ControllerDemoPage> {
@override
Widget build(BuildContext context) {
return ScaffoldMessenger(
child: Scaffold(
appBar: AppBar(),
body: ListView.builder(
itemBuilder: (context, index) {
return ListItem();
},
itemCount: 30,
),
),
);
}
}
In this case, we can only guarantee Item When it's invisible SnackBar It can pop up normally , And if we just exit the page at this time , The following error prompt will still appear , because ScaffoldMessenger Also destroyed .

So here we get the second trick : Use in asynchronous operations of(context) , It can be obtained in advance , Then do asynchronous operation , In this way, we can try our best to ensure the complete implementation of the process .
Since we are talking about passing of(context) Go to get the upper level share and the lower level share InheritedWidget , Where to get it is better ?
Remember the front log Do you ? When the first example goes wrong ,log There is a method in , That is to say State Of didChangeDependencies Method .

Why does the official suggest calling in this method of(context) ?
First of all, we have been saying , adopt of(context) What you get is InheritedWidget , and When InheritedWidget When there is a change , It is bound by triggering Element in State Of didChangeDependencies To trigger the update , So in didChangeDependencies Call inside of(context) There is a good causal relationship .
Interested in this part , You can see Flutter The trick is MediaQuery and build Optimize the secrets you don't know and Fully understand State And Provider .
Then I can initState Call in advance ?
Of course not , First, if in initState Call directly, such as ScaffoldMessenger.of(context).showSnackBar Method , You will see the following error prompt .

This is because Element I will judge this time _StateLifecycle state , If this is _StateLifecycle.created perhaps _StateLifecycle.defunct , That is to say initState and dispose , Is not allowed to execute of(context) operation .

of(context)Operation meanscontext.dependOnInheritedWidgetOfExactTyp.
Of course , If you just want to initState It's OK to adjust , Add one more Future The execution can be successful
@override
void initState() {
super.initState();
Future((){
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text("initState")));
});
}
Simple understanding , because Dart It is a single thread polling execution ,
initStateInsideFutureEquivalent to the next poll , Of course not_StateLifecycle.createdUnder the state of .
Then I am build Can't you call directly in ?
Directly in build Calling in is sure to , although build Will be executed more frequently , however of(context) Operation is actually in a map Pass through key - value Get generic objects , So it won't have much impact on performance .
The real impact on performance is of(context) The number of bindings and the custom logic after getting the object , For example, you go through MediaQuery.of(context).size After getting the screen size , Locate your controls through a series of complex calculations .
@override
Widget build(BuildContext context) {
var size = MediaQuery.of(context).size;
var padding = MediaQuery.of(context).padding;
var width = size.width / 2;
var height = size.width / size.height * (30 - padding.bottom);
return Container(
color: Colors.amber,
width: width,
height: height,
);
}
For example, the above code , It may cause the keyboard to pop up , Although the current page is not fully displayed , But it will also cause your control to constantly recalculate, resulting in jamming .
Detailed explanation can refer to Flutter The trick is MediaQuery and build Optimize the secrets you don't know
So here we have another trick : about of(context) The related operation logic of , Try to put didChangeDependencies Go and deal with it .
Last , Today, I mainly shared using BuildContext Some precautions and skills in , If you have any questions about this , Feel free to leave a comment .
边栏推荐
- 聊聊sql优化的15个小技巧
- InTouch advanced alarm (alarm filtering)
- [Detr for 3D object detection] 3detr: an end to end transformer model for 3D object detection
- KCon 2022 亮点及议程大揭秘!
- GBASE 8s UDR内存管理_01_mi_alloc
- 小程序毕设作品之微信校园维修报修小程序毕业设计成品(2)小程序功能
- 无惧高温暴雨,有孚网络如何保您无忧?
- 基于PHP的中非南南合作信息交流平台网站建设
- Real estate industry reshuffle
- [web technology] 1391 page visualization building tool, previous life and present life
猜你喜欢

Intouch高级报警(报警筛选)

【Web技术】1391- 页面可视化搭建工具前生今世

聊聊接口性能优化的11个小技巧

常用的开发软件下载地址

网络数据包多层传输演示

基础乐理--配置和弦

基于PHP的中非南南合作信息交流平台网站建设

Imeta | sangerbox: interactive integrated clinical information analysis platform

Small program completion work wechat campus maintenance application small program graduation design finished product (2) small program function

The second "future Cup" knowledge map championship was officially launched
随机推荐
TypeError: ‘str‘ object is not callable的错误原因
Wechat campus maintenance and repair applet graduation design finished product (7) Interim inspection report
[server data recovery] a data recovery case of a brand ProLiant server raid paralysis, database file loss, and database file backup damage
[Detr for 3D object detection] 3detr: an end to end transformer model for 3D object detection
Swift 基础 Codable(JSONEncoder JSONDecoder)的使用
微信小程序 26 播放音乐页的完善②
Improvement of wechat applet 29 hot search list ②
C 调的满级和玄
有孚原力超算,为客户提供定制化高性能计算服务
微信小程序 28 热搜榜的完善①
【刷题记录】21. 合并两个有序链表
聚智云算,向新而生| 有孚网络“专有云”开启新纪元
MES管理系统有什么应用价值
leetcode刷题:动态规划07(不同的二叉搜索树)
无惧高温暴雨,有孚网络如何保您无忧?
【DETR用于3D目标检测】3DETR: An End-to-End Transformer Model for 3D Object Detection
新瓶装老酒--近期APT32(海莲花)组织攻击活动样本分析
The second "future Cup" knowledge map championship was officially launched
Monitor MySQL based on MySQL exporter
高并发下如何保证数据库和缓存双写一致性?