조용한 담장

Flutter : BuildContext 본문

Flutter

Flutter : BuildContext

iosroid 2019. 9. 5. 14:47

flutter BuildContext

null error 발생

뜬금없이 null 과 관련된 에러가 발생했다.

════════ Exception Caught By gesture ═══════════════════════════════════════════════════════════════
The following NoSuchMethodError was thrown while handling a gesture:
The method 'save' was called on null.
Receiver: null
Tried calling: save()

대략 Scaffold.of(context) 식의 코드인데 리턴값이 null 인데 method를 호출하려 해서 나는 거였다.

context 값에 문제가 있었는데 BuildContext 에 대한 이해가 좀 더 필요했었다.

BuildContext

BuildContext 페이지를 천천히 읽어보니 모호한 부분에 대해 설명이 되어 있었다.


A handle to the location of a widget in the widget tree.


BuildContext 는 widget tree 에서 현재 widget 의 위치를 알 수 있는 정보가 되는데, 이 값을 코드 내에서 헷갈리게 쓸 수 있다.

예제로 쓴 코드를 가져와 보자.

// Widget Q

@override
Widget build(BuildContext context) {
  // here, Scaffold.of(context) returns null
  return Scaffold(
    appBar: AppBar(title: Text('Demo')),
    body: Builder(
      builder: (BuildContext context) {
        return FlatButton(
          child: Text('BUTTON'),
          onPressed: () {
            // here, Scaffold.of(context) returns the locally created Scaffold
            Scaffold.of(context).showSnackBar(SnackBar(
              content: Text('Hello.')
            ));
          }
        );
      }
    )
  );
}

build method 의 context 와 build method 가 리턴하는 Scaffold widget 안에서 쓰이는 context 가 다른 것이 포인트다.

코드만 봤을때는 build method 의 context 와 그 안에서 가져다 쓰는 context 가 같은거 아닌가? 부모 자식 같은 사이라 공유되는거 아닌가? 했다...


Each widget has its own BuildContext, which becomes the parent of the widget returned by the StatelessWidget.build or State.build function.

In particular, this means that within a build method, the build context of the widget of the build method is not the same as the build context of the widgets returned by that build method.


일단 BuildContext 는 모든 widget이 각각 자신의 것을 가지고 있으니, build method 를 가진 widget Q 의 BuildContext 와 widget Q 의 build method 가 생성해서 리턴하는 새로운 Scaffold widget 의 BuildContext 는 당연히 다른 것이다.

Scaffold widget 안에서 쓰인 context 가 widget Q 의 것이기 때문에 문제가 된 것이다.

이게 왜 문제가 될까?

위의 예제 코드는 Builder를 써서 문제를 해결한 것이고 원래는 아래처럼 써서 문제가 발생했을 것이다. 나처럼..

// Widget Q

@override
Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(title: Text('Demo')),
    body: FlatButton(
      child: Text('BUTTON'),
      onPressed: () {
        Scaffold.of(context).showSnackBar(SnackBar(
          content: Text('Hello.')
        ));
      }
    )
  );
}

flutter 가 하게 될 일을 상상해 보면,

Scaffold.of(context).showSnackBar 를 수행할 때 widget tree 에서 Scaffold widget 을 찾아볼 것이다.

이때 context 는 widget Q 의 것이기 때문에 widget tree에 Scaffold가 없다!

또는 widget tree 에서 부모 widget 들을 따라 Scaffold를 찾아보겠지만 없다.

그래서 null 이 리턴된다.

Builder 를 쓰면 Builder widget 은 Scaffold widget 의 자식이 되고 그때 Builder 자신의 context 를 Scaffold.of(context) 가 사용하게 되므로 widget tree에서 Scaffold 를 찾을 수 있게 된다.

BuildContext 가 widget tree 에서 해당 widget의 location 정보를 가지고 있다고 했으니, 잘못된 context를 쓰게 되면 엉뚱한 위치에서 widget 을 찾게 될 것이다.


For example, in the following snippet, the ScaffoldState.showSnackBar method is called on the Scaffold widget that the build method itself creates. If a Builder had not been used, and instead the context argument of the build method itself had been used, no Scaffold would have been found, and the Scaffold.of function would have returned null.


Reference

https://api.flutter.dev/flutter/widgets/BuildContext-class.html

'Flutter' 카테고리의 다른 글

Flutter : Form  (0) 2019.09.06
Flutter : TextField  (0) 2019.09.06
ListView  (0) 2019.08.08
url_launcher  (0) 2019.08.07
Flutter : Platform-specific code  (0) 2019.08.06
Comments