Flutter中的BuildContext到底是什么

cubegao 2021-03-11 PM 568℃ 0条

前言

首先我们看看官方的定义:

[BuildContext] objects are actually [Element] objects. The [BuildContext]
interface is used to discourage direct manipulation of [Element] objects.
[BuildContext] 对象实际上是 [Element] 对象。 [BuildContext] 接口用于阻止直接操作 [Element] 对象。

根据官方这段注释,可以了解到BuildContext 实际上就是 Element 对象,产生的意义主要是为了防止开发者直接操作 Element 对象。

如何使用BuildContext

写一段大家很熟悉的代码

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }
}
这里有同学好奇,_counter++;不写在setState的回调方法里可以生效吗?答案是可以的。但是我更推荐把和状态更新相关的操作,放在回调里面。这样更加的工程化管理。因为一个项目经过长时期的更新,你可能无法分清,这个方法里面的setState,是不是实际上起作用了,会造成代码冗余。

上面的代码也可以写成这样

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
      _counter++;
      (context as Element).markNeedsBuild();
  }
}

为什么会有同样的作用呢?那我们看看setState的源码吧

void setState(VoidCallback fn) {
  assert(fn != null);
  assert(() {
    if (_debugLifecycleState == _StateLifecycle.defunct) {
     ///......
    }
    if (_debugLifecycleState == _StateLifecycle.created && !mounted) {
     ///......
    }
    return true;
  }());
  final dynamic result = fn() as dynamic;
  assert(() {
    if (result is Future) {
      ///......
      ]);
    }
    return true;
  }());
  _element!.markNeedsBuild();
}

那么我们就清楚了,BuildContext实际上就是Widget树中特定位置所对应的实例Element

使用BuildContext时,应该注意作用域

举个例子

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context){
    return MaterialApp(
      title: 'Test Flutter',
      home: Scaffold(
        body: Center(
          child: FlatButton(
              onPressed: () {
                Navigator.of(context).push(
                    MaterialPageRoute(builder: (context) => NewWidget()));
              },
              child: Text('跳转到新页面')),
        ),
      ),
    );
  }
}
class NewWidget extends StatelessWidget {
  @override
  Widget build (BuildContext context){
    return Scaffold(
      appBar: AppBar(
        title: Text("this is title"),
      ),
      body: Center(
        child: Text("this is body"),
      ),
    );
  }
}

运行一下,发现会报错:提示当前的context找不到Navigator
我们知道NavigatorMaterialApp为我们提供的,但是当前的调用的context,实际上是MyApp拥有的实例,并不是MaterialApp对应的context
那我们可以改造一下:

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context){
    return MaterialApp(
      title: 'Test Flutter',
      home: Scaffold(
        body: Center(
          child: Builder(
          builder: (context) {
            return FlatButton(
                  onPressed: () {
                    Navigator.of(context).push(
                        MaterialPageRoute(builder: (context) => NewWidget()));
                  },
                  child: Text('跳转到新页面')),
                ),
              );
          },
        ),
    );
  }
}
标签: Flutter, BuildContext

非特殊说明,本博所有文章均为博主原创。

评论啦~