Element Tree, Flutter'da bildirimsel Widget Tree ile zorunlu RenderObject Tree'yi birbirine bağlayan bir ara katmandır. Her yeniden yapılandırmada yeniden oluşturulan widget'ların aksine, öğeler güncellemeler arasında kalıcı olur ve durum, anahtarlar ve yaşam döngüsünü yönetir. Flutter API Reference, 2025'e göre, Element Tree'yi anlamak, anahtarlarla etkili çalışmak, performansı optimize etmek ve beklenmeyen widget davranışlarını hata ayıklamak için gereklidir.
Önemli Noktalar
Element Tree, Widget Tree temel alınarak oluşturulan ve widget'ların uygulamaya yerleştirilmesini yöneten Flutter'daki bir ara hiyerarşidir. Her öğe örneği, ağaçtaki bir widget'a karşılık gelir ve ona bir referans saklar. Bir öğe ile widget arasındaki temel fark, öğenin yeniden yapılandırmalar arasında ağaçtaki konumunu koruması, oysa widget'ın her build çağrısında yeniden oluşturulabilmesidir.
Element Tree olmadan, Flutter kullanıcı arayüzünü verimli bir şekilde güncelleyemezdi. Her yeniden yapılandırma RenderObject Tree'yi yeniden oluştursaydı, performans kabul edilemez derecede düşük olurdu. Element Tree bir dengeleyici görevi görür: güncellemeler arasında RenderObject ve State'e referansları tutar ve Flutter'ın render ağacına yalnızca minimum değişiklikleri uygulamasına izin verir.
Flutter üç ana öğe türü kullanır: StatelessWidget için StatelessElement, StatefulWidget için StatefulElement ve RenderObjectWidget için LeafRenderObjectElement, SingleChildRenderObjectElement, MultiChildRenderObjectElement. Her tür, widget sınıfı için uzmanlaşmıştır ve öğenin RenderObject ile nasıl etkileşime gireceğini belirler.
Üç katmanlı mimari, Flutter'da Widget Tree (yapılandırma), Element Tree (yönetim) ve RenderObject Tree (render) olmak üzere üç katmandan oluşur. Element Tree bağlantı halkasıdır: Widget'tan yapılandırmayı okur ve RenderObject'a komutlar iletir. Element Tree olmadan, çerçeve bildirimsel tanımı gerçek render ile verimli bir şekilde senkronize edemezdi.
Bir öğe ağaca monte edildiğinde, widget türünü kontrol eder. Widget bir RenderObjectWidget ise, öğe ilgili RenderObject'u oluşturur ve RenderObject Tree'ye ekler. Widget bir LeafRenderObjectWidget ise, öğe bir yaprak RenderObject oluşturur. StatelessWidget ve StatefulWidget için öğe yalnızca alt öğelerin montajını yönetir.
abstract class Element {
Widget widget;
Element? parent;
List<Element>? children;
void mount(Element? parent, dynamic newSlot);
void update(Widget newWidget);
void unmount();
}
Bu basitleştirilmiş kod, Element'in temel yapısını gösterir. Her öğe, geçerli widget'a, üst öğeye ve alt öğelere bir referans saklar. mount, update ve unmount yöntemleri, öğenin ve ilişkili RenderObject'unun yaşam döngüsünü yönetir.
Her öğe Flutter'da bir dizi yaşam döngüsü aşamasından geçer: oluşturma, monte etme, güncelleme ve monte etmeme. Bu aşamaları anlamak, özellikle animasyonlar, asenkron işlemler ve durum yönetimi ile çalışırken beklenmeyen davranışlarda hata ayıklamak için gereklidir.
Bir öğe, widget'ın createElement yöntemi çağrılarak oluşturulur. StatelessWidget için bir StatelessElement oluşturulur; StatefulWidget için bir StatefulElement (ayrıca bir State nesnesi oluşturur) oluşturulur. RenderObjectWidget için ilgili RenderObjectElement oluşturulur. Öğe oluşturma, widget Widget Tree'de ilk kez göründüğünde gerçekleşir.
Monte etme sırasında, öğe Element Tree'ye eklenir ve bir üst öğe alır. RenderObjectElement için monte etme ayrıca bir RenderObject oluşturur ve onu RenderObject Tree'ye ekler. Widget bir StatefulWidget ise, bu aşamada State nesnesinin initState yöntemi çağrılır.
Widget yeni bir yapılandırmayla yeniden oluşturulduğunda, öğe yeni widget'ı update yöntemi aracılığıyla alır. Öğe, eski ve yeni widget'ın türünü karşılaştırır: türler eşleşirse, öğe yapılandırmasını günceller; eşleşmezse, öğe monte edilmez ve yeni bir öğe oluşturulur. Buna "widget değişikliği" denir ve tür değiştirirken durum kaybının nedenidir.
Widget Widget Tree'den kaldırıldığında, öğenin unmount yöntemi çağrılır. Öğe Element Tree'den kaldırılır, RenderObject RenderObject Tree'den kaldırılır ve StatefulWidget için State nesnesinin dispose yöntemi çağrılır. Monte etmeme sonrasında, widget aynı konumda tekrar görünürse öğe yeniden kullanılabilir.
Anahtarlar (Key), Flutter'ın eski ve yeni Widget Tree'deki widget'ları konuma göre değil, benzersiz bir tanımlayıcıya göre eşleştirmesini sağlayan bir öğe tanımlama mekanizmasıdır. Anahtarlar, öğelerin sırasının değişebileceği dinamik listelerle (öğe ekleme, kaldırma veya yeniden düzenleme) çalışırken kritik öneme sahiptir.
Anahtar olmadan, Flutter öğeleri ağaçtaki konumlarına göre eşleştirir: eski ağaçtaki 0 konumundaki öğe, yeni ağaçtaki 0 konumundaki widget ile değiştirilir. Sıra değişmişse, öğeler karışır ve durum kaybolabilir veya yanlış verilere bağlanabilir. Bir anahtar, Flutter'ı konum yerine tanımlayıcıya göre öğe aramaya zorlar.
ValueKey, bir öğeyi tanımlamak için basit bir değer (dize, sayı) kullanır. ObjectKey bir nesne referansı kullanır — öğenin kararlı bir dize tanımlayıcısı olmadığında uygundur. UniqueKey her oluşturmada benzersiz bir tanımlayıcı üretir — her widget örneği benzersiz olması gerektiğinde kullanılır.
Column(
children: items.map((item) => TodoItem(
key: ValueKey(item.id),
title: item.title,
isDone: item.isDone,
)).toList(),
)
Bu örnekte, item.id ile ValueKey, listedeki öğelerin sırası değiştiğinde her TodoItem'ın durumunu (örneğin, giriş alanı odağı) korumasını sağlar. Anahtar olmadan, ilk konumdaki öğe, aynı konumdaki önceki öğenin durumunu alırdı.
Flutter'da durum (State) widget'larda değil, öğelerde saklanır. Bir StatefulWidget yeniden oluşturulduğunda ve yeni bir widget örneği oluşturduğunda, ilgili StatefulElement eski State nesnesine bir referans tutar. Yeni widget, mevcut State'e bağlanarak verilerin yeniden yapılandırmalar arasında korunmasını sağlar.
Bir widget yeniden yapılandırılırken, Flutter yeni bir StatefulWidget örneği oluşturur, ancak ilgili StatefulElement Element Tree'de kalır. Öğe, State üzerinde update yöntemini çağırarak yeni widget'ı iletir. Böylece State nesnesi ve verileri korunur. Durum kaybı yalnızca widget türü değiştiğinde, anahtar değiştiğinde veya öğe ağaçtan kaldırıldığında meydana gelir.
InheritedElement, alt öğelerin kurucular aracılığıyla açıkça iletme olmadan bir üst InheritedWidget'tan veri almasını sağlayan özel bir öğedir. InheritedWidget değiştiğinde, InheritedElement tüm bağımlı öğeleri bildirir ve bunlar yeniden oluşturulur. Bu mekanizma Theme, MediaQuery ve Provider'ın temelini oluşturur.
Element Tree bellek tüketir ve ilk render hızını etkiler. Her öğe belirli bir miktar bellek kaplar: widget'a referans, üst öğeye referans, alt öğeler listesi, bir yuva ve RenderObjectElement için ek alanlar. Element Tree'yi optimize etmek, başlangıç süresini kısaltır ve bellek tüketimini azaltır.
Flutter, yeniden yapılandırma sırasında öğeleri yeniden kullanmaya çalışır. Yeni yapılandırmadaki widget aynı tür ve anahtara sahipse, öğe yeniden oluşturulmaz — güncellenir. Bu, yeni bir öğe oluşturup ardından monte etmekten önemli ölçüde daha hızlıdır. Ancak, tür veya anahtar değiştiğinde, eski öğe monte edilmez ve sıfırdan yeni bir öğe oluşturulur.
RepaintBoundary, RenderObject Tree'de ağacın bir bölümünü izole eden ayrı bir RenderRepaintBoundary oluşturur. Element Tree düzeyinde, RepaintBoundary özel bir öğe oluşturmaz — SingleChildRenderObjectElement kullanır. Fark, RenderObject düzeyinde ortaya çıkar: RepaintBoundary içeriği değiştiğinde, yalnızca izole edilmiş alan yeniden boyanır.
| İşlem | RepaintBoundary Yok | RepaintBoundary Var |
|---|---|---|
| Yeniden Boyama | Tüm ekran | Yalnızca izole alan |
| Süre | 60 FPS'de ~16 ms | ~2-5 ms |
| Bellek | Minimum | + katman başına birkaç KB |
Tabloda görüldüğü gibi, RepaintBoundary değişen alanı izole ederek yeniden boyama süresini önemli ölçüde azaltır. Element Tree düzeyinde, bu ek yapılandırma gerektirmez — değişken widget'ı RepaintBoundary içine sarmak yeterlidir.
Sıkça Sorulan Sorular
Widget Tree, her yeniden yapılandırmada yeniden oluşturulan bir yapılandırmadır. Element Tree, güncellemeler arasında kalan ve durumu, RenderObject'u ve widget yaşam döngüsünü yöneten kalıcı bir yapıdır.
Element Tree olmadan, Flutter her durum değişikliğinde RenderObject Tree'yi yeniden oluşturmak zorunda kalırdı, bu da önemli gecikmelere neden olurdu. Element Tree, RenderObject ve State'i koruyarak yalnızca minimum değişikliklerin uygulanmasına izin verir.
Bir öğe, ilgili widget Widget Tree'den kaybolduğunda veya widget türü değiştiğinde (örneğin, Column'ın Row ile değiştirilmesi) veya anahtar değiştiğinde kaldırılır. Monte etmeme sırasında State üzerinde dispose çağrılır.
Anahtarlar eşleştirme algoritmasını değiştirir: Flutter konuma göre öğe aramak yerine anahtar değerine göre öğe arar. Bu, widget'ların sırası veya miktarı değiştiğinde durumun korunmasını sağlar.
Evet, BuildContext aracılığıyla, bir öğenin soyutlamasıdır. findAncestorWidgetOfExactType ve dependOnInheritedWidgetOfExactType yöntemleri, öğe ağacında yukarı doğru ilerleyerek Element Tree ile çalışır.
Özet
Anahtar teslim bir mobil uygulama geliştireceğiz
IT Sectr, 2017'den beri girişimler ve işletmeler için iOS ve Android uygulamaları oluşturmaktadır. Size danışmanlık yapacak ve en iyi çözümü önereceğiz.
Ayrıca okuyun