Flutter Architecture
Understanding how Flutter works under the hood
🏗️ Flutter Architecture
Flutter uses a layered architecture with Framework layer for widgets, Engine layer for rendering, and Embedder layer for platform integration. Everything renders through Skia graphics engine for native performance.
// Flutter's widget tree architecture
MaterialApp
└── Scaffold
├── AppBar
└── Body
└── Column
├── Text
└── Button
// Everything is a widget!
Flutter Layers
Framework Layer
Dart code, widgets, and libraries
// Written in Dart
Text()
Container()
Scaffold()
Engine Layer
C++ rendering engine with Skia
Skia Graphics
Dart Runtime
Text Layout
Embedder Layer
Platform-specific code
Android (Java/Kotlin)
iOS (Objective-C/Swift)
Windows/Linux/Mac
Platform Channels
Communication bridge
// Access native APIs
MethodChannel
EventChannel
🔹 Widget Tree Architecture
Flutter builds UI using three trees:
1. Widget Tree (Configuration)
// Widgets are immutable configurations
class MyWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
child: Text('Hello'),
);
}
}
// Widget tree:
// Container
// └── Text
2. Element Tree (Lifecycle)
// Elements manage widget lifecycle
// Created automatically by Flutter
// Links widgets to render objects
// Element tree mirrors widget tree
// ContainerElement
// └── TextElement
3. Render Tree (Painting)
// Render objects handle layout and painting
// Optimized for performance
// Render tree:
// RenderContainer
// └── RenderParagraph
🔹 How Flutter Renders UI
Understanding the rendering pipeline:
Rendering Steps:
- Build: Widgets create element tree
- Layout: Calculate size and position
- Paint: Draw widgets on screen
- Composite: Combine layers
- Rasterize: Convert to pixels (Skia)
// Flutter's rendering process
Widget build() → Element → RenderObject → Paint → Screen
// Example:
Text('Hello') // Widget
→ TextElement // Element
→ RenderParagraph // RenderObject
→ Canvas.drawText // Paint
→ Screen pixels // Display
🔹 Stateless vs Stateful Widgets
Two types of widgets in Flutter:
🔸 Stateless Widget (Immutable)
// Never changes after creation
class MyStatelessWidget extends StatelessWidget {
final String title;
MyStatelessWidget({required this.title});
@override
Widget build(BuildContext context) {
return Text(title);
}
}
// Use for: Static content, labels, icons
🔸 Stateful Widget (Mutable)
// Can change over time
class MyStatefulWidget extends StatefulWidget {
@override
_MyStatefulWidgetState createState() => _MyStatefulWidgetState();
}
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
int counter = 0;
void increment() {
setState(() {
counter++;
});
}
@override
Widget build(BuildContext context) {
return Column(
children: [
Text('Count: $counter'),
ElevatedButton(
onPressed: increment,
child: Text('Increment'),
),
],
);
}
}
// Use for: Interactive UI, forms, animations
Output:
Count: 0
🔹 State Management
Managing state in Flutter apps:
// setState() - Simple state management
class Counter extends StatefulWidget {
@override
_CounterState createState() => _CounterState();
}
class _CounterState extends State<Counter> {
int count = 0;
@override
Widget build(BuildContext context) {
return Column(
children: [
Text('$count'),
ElevatedButton(
onPressed: () {
setState(() {
count++; // Update state
});
},
child: Text('+'),
),
],
);
}
}
// setState() triggers rebuild of widget
🔹 BuildContext Explained
Understanding BuildContext:
// BuildContext represents widget's location in tree
class MyWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
// context gives access to:
// 1. Theme data
final theme = Theme.of(context);
// 2. Media query (screen size)
final size = MediaQuery.of(context).size;
// 3. Navigation
Navigator.of(context).push(...);
// 4. Inherited widgets
final data = MyInheritedWidget.of(context);
return Container();
}
}
🔹 Widget Lifecycle
Stateful widget lifecycle methods:
class MyWidget extends StatefulWidget {
@override
_MyWidgetState createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
@override
void initState() {
super.initState();
// Called once when widget is created
print('Widget initialized');
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
// Called when dependencies change
}
@override
Widget build(BuildContext context) {
// Called every time widget needs to rebuild
return Container();
}
@override
void didUpdateWidget(MyWidget oldWidget) {
super.didUpdateWidget(oldWidget);
// Called when widget configuration changes
}
@override
void dispose() {
// Called when widget is removed
print('Widget disposed');
super.dispose();
}
}
🔹 Platform Channels
Communicating with native code:
import 'package:flutter/services.dart';
// Create a method channel
class BatteryLevel {
static const platform = MethodChannel('samples.flutter.dev/battery');
Future<int> getBatteryLevel() async {
try {
final int result = await platform.invokeMethod('getBatteryLevel');
return result;
} catch (e) {
print('Error: $e');
return -1;
}
}
}
// Use in widget
ElevatedButton(
onPressed: () async {
final battery = BatteryLevel();
final level = await battery.getBatteryLevel();
print('Battery: $level%');
},
child: Text('Get Battery'),
)
🔹 Flutter Architecture Benefits
Why Flutter's Architecture is Powerful:
- Fast Rendering: Direct compilation to native code
- Hot Reload: Instant updates without losing state
- Consistent UI: Same widgets on all platforms
- Customizable: Full control over every pixel
- Reactive: UI automatically updates with state changes