DanT29
DanT29

Reputation: 3229

Where is context getting passed in?

Consider the following code:

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Welcome to Flutter',
      home: new Scaffold(
        appBar: new AppBar(
          title: new Text('Welcome to Flutter'),
        ),
        body: new Center(
          child: new Text('Hello World'),
        ),
      ),
    );
  }
}

My understanding of Buildcontext is that it is the "context" of the widget (please correct me if I'm wrong or elaborate further). What I don't understand is how is the argument "context" passed into the method. Does the runApp function supply the "context"?

Upvotes: 1

Views: 1227

Answers (1)

Mikolaj Kieres
Mikolaj Kieres

Reputation: 4405

TLDR: This is controlled by the framework.

For those who like reading:

Starting from the very beginning. The runApp method takes your app widget and inserts it into the tree, as per comment on the method (binding.dart):

Inflate the given widget and attach it to the screen.

When that's being done, the app StatelessWidget (which obviously is a Widget) is being inflated into an Element (Widget class comments in framework.dart file)

Each time a widget is placed in the tree, it is inflated into an [Element], which means a widget that is incorporated into the tree multiple times will be inflated multiple times.

If you then have a look at the abstract class Element, in the same GitHub repo file (framework.dart), you will see the comments above it, saying:

Elements have the following lifecycle:

  • The framework creates an element by calling [Widget.createElement] on the widget that will be used as the element's initial configuration.
  • The framework calls [mount] to add the newly created element to the tree at a given slot in a given parent. The [mount] method is responsible for inflating any child widgets and calling [attachRenderObject] as necessary to attach any associated render objects to the render tree.

These two methods createElement and mount are the ones that are responsible for calling the build method.

If you have a look at the the StatelessWidget class, you will see that it has an override for createElement method (framework.dart). Which creates StatelessElement object and passes itself (this) as a constructor parameter. Notice, how the StatelessElement class overrides the build method and calls widget.buildmethod (in this case, the widget is your app widget - i.e. MyApp). This still doesn't tell us how the build method is called though. If you drill down a bit deeper, into the ComponentElement (class that StatelessElement derives from - framework.dart), you can see the mount method being overridden. In this method (which is invoked by the framework), there's a call to _firstBuild method, which then calls rebuild, this method then calls performRebuild method, which finally ends up invoking the build method.

Easy, right?

DISCLAIMER: This is just me connecting the dots. I'm not an expert on Flutter - I literally started using Flutter a week ago. It would be good if some more experienced devs could confirm or not, if my understanding of the mechanisms behind widgets is correct.

EDIT: Answering comment questions

  1. Inflating (in my mind) is creating the object in the memory (so that framework has a reference of it) and rendering it on the screen.

  2. Yes, the BuildContextis going to be the StatelessElement, which contains a reference to the app itself

Debugging with VS Code - Flutter Redux architecture sample

Upvotes: 5

Related Questions