Rebuild performansı və ölçmə
State management-in performans təsiri bir sualla ölçülür: bir dəyişiklik nə qədər widget-i oyadır? Rəsmi performans tövsiyələri bu istiqamətdə konkretdir:
- Widget-lərdə mümkün olduqca `const` konstruktorlardan istifadə edin — bu, Flutter-in rebuild işinin böyük hissəsini qısa yolla keçməsinə imkan verir.
flutter_lintspaketi bunu avtomatik xatırladır. - `build()` metodlarında təkrarlanan və bahalı işdən çəkinin, çünki ata widget-lər yenidən qurulduqda `build()` tez-tez çağırıla bilər.
- Böyük `build()` funksiyası olan həddindən artıq iri widget-lərdən çəkinin; onları həm enkapsulyasiyaya, həm də necə dəyişdiklərinə görə bölün. Sənəd əlavə edir:
setState()çağırıldıqda bütün alt ağac yenidən qurulur, ona görə çağırışı dəyişən hissəyə yaxın saxlamaq lazımdır. - Təkrar istifadə olunan UI hissələri üçün funksiya yerinə `StatelessWidget` seçin.
- Böyük siyahı və grid-lərdə lazy builder metodlarından istifadə edin — yalnız ekranda görünən hissə qurulur.
| Library | Rebuild sahəsini daraltmaq üçün alət |
|---|---|
| Flutter (library-siz) | `setState`-i aşağı çəkmək, `ValueListenableBuilder`, `const`, `ListenableBuilder` |
| Provider | `Consumer` (`child` parametri ilə), `Selector`, `context.select` |
| Riverpod | `Consumer` widget-i, `provider.select(...)`, ayrı-ayrı kiçik provider-lər |
| BLoC | `BlocSelector`, `buildWhen`, `BlocBuilder`-i dərinə yerləşdirmək |
Ölçmə: təxminlə optimizasiya etməyin. DevTools-un Performance görünüşü rebuild-ləri tapmaq üçün konkret seçimlər verir:
- Track Widget Builds —
build()metod hadisələrini timeline-da göstərir; hadisənin adında widget-in adı olur. - Enhance tracing — daha detallı izləmə seçimləri; sənəd xəbərdarlıq edir ki, bu seçimlər aktiv olduqda frame vaxtları mənfi təsirlənə bilər.
- Track Layouts və Track Paints — render obyektlərinin layout və paint hadisələri.
Müsahibədə ardıcıllığı belə ifadə etmək güclüdür: əvvəlcə ölç, sonra rebuild sahəsini darald, sonra yenidən ölç. Optimizasiya iddiası rəqəmlə müşayiət olunmursa, o, təxmindir.
// ❌ Bütün ekran hər dəyişiklikdə qurulur:
// - watch build-in yuxarısındadır
// - ağır widget-lər eyni metodun içindədir
// - const yoxdur
class DashboardBad extends StatelessWidget {
@override
Widget build(BuildContext context) {
final model = context.watch<DashboardModel>();
return Column(
children: [
HeavyChart(data: model.chartData),
ExpensiveMap(),
Text('Bildiriş: ${model.unreadCount}'),
],
);
}
}
// ✅ Yalnız dəyişən hissə qurulur:
// - ağır widget-lər const və ya kənarda
// - abunəlik yalnız lazım olan sahəyə
class DashboardGood extends StatelessWidget {
const DashboardGood({super.key});
@override
Widget build(BuildContext context) {
return Column(
children: [
// Yalnız chartData dəyişdikdə qurulur.
Selector<DashboardModel, List<Point>>(
selector: (_, m) => m.chartData,
builder: (_, data, __) => HeavyChart(data: data),
),
const ExpensiveMap(), // heç vaxt rebuild olunmur
Selector<DashboardModel, int>(
selector: (_, m) => m.unreadCount,
builder: (_, count, __) => Text('Bildiriş: $count'),
),
],
);
}
}Eyni ekran, iki rebuild profili.
Ən çox rastlanan performans səhvi state management-də deyil, abunəliyin çox yuxarıda olmasındadır: build-in birinci sətrində bütün modeli watch etmək ekranın hər hissəsini bir dəyişikliyə bağlayır. Bu, üç library-də də eyni səhvdir və həlli də eynidir — abunəliyi ağacda aşağı çəkmək (Consumer, Selector, BlocSelector, Riverpod-da kiçik Consumer widget-ləri).
📚 Mənbələr və sənədlər
- Flutter performans ən yaxşı təcrübələrirəsmidocs.flutter.dev
const, build()-də bahalı iş, setState-in sahəsi və lazy builder tövsiyələrinin mənbəyi.
- DevTools: Performance görünüşürəsmidocs.flutter.dev
**Track Widget Builds**, **Enhance tracing**, **Track Layouts/Paints** seçimləri.
- UI performansının profillənməsirəsmidocs.flutter.dev
- RepaintBoundary APIrəsmiapi.flutter.dev
Yenidən boyanma sahəsini ayırmaq lazım olduqda — rebuild-dən fərqli bir mərhələ.