
Bagaimana cara Flutter bekerja?
Apa itu Widget, Elemen, BuildContext, RenderOject, Bindings? ..
Kesulitan: Pemula
Entri
Tahun lalu ( catatan: pada tahun 2018 ), ketika saya memulai perjalanan saya ke dunia Flutter yang luar biasa, hanya ada sedikit informasi di Internet dibandingkan dengan sekarang. Sekarang, terlepas dari kenyataan bahwa banyak materi telah ditulis, hanya sebagian kecil dari mereka yang berbicara tentang cara Flutter bekerja.
Apa itu Widget ( widget ), Elemen ( elemen ), BuildContext? Mengapa Flutter cepat? Mengapa terkadang tidak bekerja seperti yang diharapkan? Apa itu pohon dan mengapa mereka dibutuhkan?
Dalam 95% kasus saat menulis aplikasi, Anda hanya akan berurusan dengan widget untuk menampilkan sesuatu atau berinteraksi dengannya. Tetapi pernahkah Anda benar-benar bertanya-tanya bagaimana semua sihir ini bekerja di dalam? Bagaimana sistem tahu kapan harus menyegarkan layar dan bagian mana yang harus diperbarui?
Konten:
Bagian 1: Latar Belakang
Bagian pertama dari artikel ini menyajikan beberapa konsep utama yang akan digunakan pada bagian kedua dari materi dan membantu untuk lebih memahami Flutter.
Sedikit tentang perangkat
Mari kita mulai dari akhir dan kembali ke dasar.
Saat Anda melihat perangkat Anda atau, lebih tepatnya, pada aplikasi yang berjalan di perangkat Anda, Anda hanya melihat layar.
Faktanya, yang Anda lihat hanyalah piksel, yang bersama-sama membentuk gambar 2 dimensi, dan ketika Anda menyentuh layar dengan jari Anda, perangkat hanya mengenali posisi jari Anda di atas kaca.
Semua keajaiban aplikasi (dari sudut pandang visual) dalam banyak kasus adalah memperbarui gambar ini berdasarkan interaksi berikut:
- dengan layar perangkat ( misalnya, jari di atas kaca )
- dengan jaringan ( misalnya, komunikasi dengan server )
- seiring waktu ( mis. animasi )
- dengan sensor eksternal lainnya
Visualisasi gambar pada layar disediakan oleh perangkat keras (layar), yang secara teratur (biasanya 60 kali per detik) memperbarui tampilan. Ini disebut "refresh rate" dan dinyatakan dalam Hz (Hertz).
Layar menerima informasi untuk ditampilkan dari GPU (Graphics Processing Unit), yang merupakan sirkuit elektronik khusus yang dioptimalkan dan dirancang untuk dengan cepat membentuk gambar dari beberapa data (poligon dan tekstur). Jumlah kali per detik yang prosesor grafis dapat menghasilkan "gambar" (= frame buffer) untuk ditampilkan dan mengirimkannya ke perangkat keras disebut frame rate ( catatan: frame rate ). Ini diukur menggunakan blok bingkai per detik ( mis. 60 frame per detik atau 60fps ).
Anda mungkin bertanya kepada saya mengapa saya memulai artikel ini dengan konsep gambar 2 dimensi yang ditampilkan oleh GPU / perangkat keras dan sensor kaca fisik, dan apa hubungannya dengan widget Flutter biasa?
Saya pikir akan lebih mudah untuk memahami bagaimana Flutter sebenarnya bekerja jika kita melihatnya dari sudut pandang ini, karena salah satu tujuan utama aplikasi Flutter adalah untuk membuat gambar 2 dimensi ini dan memungkinkannya berinteraksi dengannya. Juga karena di Flutter, percaya atau tidak, hampir semuanya karena kebutuhan untuk memperbarui layar dengan cepat dan pada waktu yang tepat!
Antarmuka antara kode dan perangkat
Bagaimanapun, semua orang yang tertarik dengan Flutter telah melihat gambar berikut yang menggambarkan arsitektur tingkat tinggi Flutter.

Saat kami menulis aplikasi Flutter menggunakan Dart, kami tetap berada di level Flutter Framework (disorot dengan warna hijau).
Flutter Framework berinteraksi dengan Flutter Engine (berwarna biru) melalui lapisan abstraksi yang disebut Window . Level abstraksi ini menyediakan sejumlah API untuk interaksi tidak langsung dengan perangkat.
Juga melalui level abstraksi ini, Mesin Flutter memberi tahu Flutter Framework ketika:
- suatu peristiwa yang menarik terjadi pada tingkat perangkat (perubahan orientasi, perubahan pengaturan, masalah memori, kondisi operasi aplikasi ...)
- beberapa peristiwa terjadi pada level gelas (= gerakan)
- saluran platform mengirim beberapa data
- tetapi juga terutama saat Flutter Engine siap membuat bingkai baru
Kelola Kerangka Kerja Flutter rendering Engine
Sulit dipercaya, tapi itu benar. Kecuali dalam beberapa kasus ( lihat di bawah ), tidak ada kode Flutter Framework yang dijalankan tanpa memulai rendering Flutter Engine .
Pengecualian:
- Gesture / Gesture (= acara di atas kaca)
- Pesan platform (= pesan yang dihasilkan oleh perangkat, seperti GPS)
- Pesan perangkat (= pesan yang berhubungan dengan perubahan status perangkat, misalnya, orientasi, aplikasi yang dikirim di latar belakang, peringatan memori, pengaturan perangkat ...)
- Respons masa depan atau http
(Di antara kami, Anda benar-benar dapat menerapkan perubahan visual tanpa menelepon dari Flutter Engine, tetapi ini tidak disarankan )
Anda bertanya kepada saya: "Jika semacam kode yang terkait dengan gerakan dijalankan dan menyebabkan perubahan visual, atau jika saya menggunakan timer untuk mengatur frekuensi tugas yang mengarah ke perubahan visual (misalnya, animasi), lalu bagaimana cara kerjanya?"
Jika Anda ingin perubahan visual terjadi atau beberapa kode dijalankan berdasarkan timer, maka Anda perlu memberi tahu Flutter Engine bahwa ada sesuatu yang harus diambil.
Biasanya, saat berikutnya Flutter Engine memperbarui, ia memanggil Flutter Framework untuk mengeksekusi beberapa kode, dan akhirnya memberikan adegan baru untuk rendering.
Oleh karena itu, pertanyaan penting adalah bagaimana mesin Flutter mengatur semua perilaku aplikasi berdasarkan rendering.
Untuk mendapatkan gagasan tentang mekanisme internal, lihat animasi berikut:

Penjelasan singkat (detail lebih lanjut akan datang nanti):
- Beberapa peristiwa eksternal (gerakan, tanggapan http, dll.) Atau bahkan masa depan dapat memicu tugas yang membuatnya perlu untuk memperbarui tampilan. Pesan yang sesuai dikirim ke Mesin Flutter (= Jadwal Frame )
- Ketika Mesin Flutter siap untuk mulai memperbarui rendering, itu membuat permintaan Begin Frame
- Permintaan Begin Frame ini dicegat oleh Flutter Framework , yang melakukan tugas-tugas yang terutama terkait dengan Tickers (misalnya, animasi)
- Tugas-tugas ini dapat membuat kembali permintaan untuk rendering nanti (contoh: animasi belum menyelesaikan eksekusi, dan untuk menyelesaikannya, perlu mendapatkan Begin Bingkai lain pada tahap selanjutnya)
- Selanjutnya, Mesin Flutter mengirimkan Draw Frame , yang dicegat oleh Flutter Framework , yang akan mencari tugas apa pun yang berkaitan dengan memperbarui tata letak dalam hal struktur dan ukuran
- Setelah semua tugas ini selesai, ia melanjutkan ke tugas yang terkait dengan memperbarui tata letak dalam hal rendering
- Jika ada sesuatu di layar yang perlu digambar, maka adegan baru ( Scene ) untuk visualisasi dikirim ke Flutter Engine , yang akan memperbarui layar
- Flutter Framework kemudian melakukan semua tugas yang akan dilakukan setelah rendering (= callback PostFrame), dan tugas-tugas berikutnya lainnya yang tidak terkait dengan rendering
- ... dan proses ini dimulai dari awal lagi
RenderView dan RenderObject
Sebelum menyelam ke rincian alur kerja, saatnya untuk memperkenalkan konsep Pohon Rendering .
Seperti disebutkan sebelumnya, semuanya pada akhirnya akan dikonversi menjadi piksel yang akan ditampilkan di layar, dan Flutter Framework akan mengonversi Widget yang kami gunakan untuk mengembangkan aplikasi menjadi blok visual yang akan ditampilkan di layar.
Bagian visual ini sesuai dengan objek yang disebut RenderObject , yang digunakan untuk:
- mendefinisikan area layar tertentu dalam hal ukuran, posisi, geometri, serta dalam hal "konten yang diberikan"
- mengidentifikasi area layar yang dapat dipengaruhi oleh gerakan (= sentuhan jari)
Satu set semua RenderObjects membentuk pohon yang disebut Render Tree . Di atas pohon ini (= root ) kami menemukan RenderView .
RenderView menyediakan permukaan umum untuk objek Render Tree dan merupakan versi khusus RenderObject .
Secara visual, kami dapat mewakili semua ini sebagai berikut:

Hubungan antara Widget dan RenderObject akan dibahas nanti. Sementara itu, saatnya untuk pergi sedikit lebih dalam ...
Binding inisialisasi
Ketika aplikasi Flutter dimulai, fungsi main()
dipanggil pertama, yang akhirnya memanggil metode runApp(Widget app)
.
Ketika metode runApp()
Flutter Framework menginisialisasi antarmuka antara dirinya dan Flutter Engine . Antarmuka ini disebut binding ( catatan: binding ).
Pengantar Bindings
Binding dirancang untuk menjadi penghubung antara kerangka dan mesin Flutter. Hanya melalui binding data dapat dipertukarkan antara Flutter Framework dan Flutter Engine .
(Hanya ada satu pengecualian untuk aturan ini - RenderView , tetapi kami akan membahas ini nanti).
Setiap penjilidan bertanggung jawab untuk memproses serangkaian tugas, tindakan, peristiwa tertentu, dikelompokkan berdasarkan bidang kegiatan.
Pada saat penulisan ini, Flutter Framework memiliki 8 binding.
Di bawah ini adalah 4 di antaranya yang akan dipertimbangkan dalam artikel ini:
- Penjadwal Penjilidan
- Mengikat gerakan
- Pengikat penyaji
- Penjilidan widget
Untuk kelengkapan, saya akan menyebutkan 4 sisanya:
- ServicesBinding : bertanggung jawab untuk memproses pesan yang dikirim oleh saluran platform
- PaintingBinding : bertanggung jawab untuk memproses cache gambar
- SemanticsBinding : dicadangkan untuk implementasi selanjutnya dari segala sesuatu yang berkaitan dengan semantik
- TestWidgetsFlutterBinding : digunakan oleh perpustakaan tes widget
Anda juga dapat menyebutkan WidgetsFlutterBinding , tetapi ini bukan benar-benar mengikat, melainkan semacam "penginisialisasi mengikat . "
Diagram berikut menunjukkan interaksi antara binding, yang akan saya pertimbangkan selanjutnya, dan Flutter Engine .

Mari kita lihat masing-masing ikatan "inti" ini.
Penjadwal Penjilid
Ikatan ini memiliki dua tanggung jawab utama:
- Katakan Mesin Flutter : "Hei! Lain kali ketika Anda tidak sibuk, bangunkan saya agar saya bisa bekerja sedikit dan memberi tahu Anda apa yang harus dirender, atau jika saya perlu Anda menelepon saya nanti ..."
- Dengarkan dan tanggapi “kebangkitan yang mengganggu” tersebut (lihat di bawah)
Kapan SchedulerBinding meminta panggilan bangun ?
Kapan Ticker Harus Mengerjakan Tick Baru
Misalnya, Anda memiliki animasi, Anda memulainya. Animasi dipangkas menggunakan Ticker , yang dipanggil secara berkala (= centang ) untuk melakukan panggilan balik . Untuk meluncurkan panggilan balik seperti itu, kami perlu memberi tahu Flutter Engine agar ia bangun selama pembaruan berikutnya (= Mulai Frame ). Ini akan meluncurkan panggilan balik ticker untuk menyelesaikan tugasnya. Jika ticker masih perlu melanjutkan eksekusi, maka di akhir tugasnya, ia akan memanggil SchedulerBinding untuk menjadwalkan frame lain.
Kapan harus memperbarui tampilan
Sebagai contoh, kita perlu membuat suatu peristiwa yang mengarah pada perubahan visual (contoh: memperbarui warna bagian layar, menggulir, menambahkan / menghapus sesuatu dari layar), untuk ini kita perlu mengambil langkah-langkah yang diperlukan untuk akhirnya menampilkan gambar yang diperbarui pada layar. Dalam hal ini, ketika perubahan tersebut terjadi, Kerangka Flutter memanggil Penjadwal untuk mengikat frame lain menggunakan Mesin Flutter . (Nanti kita akan melihat bagaimana ini sebenarnya bekerja)
Mengikat gerakan
Ikatan ini mendengarkan interaksi dengan mesin dalam hal “jari” (= gesture ).
Secara khusus, ia bertanggung jawab untuk menerima data terkait jari dan untuk menentukan bagian layar mana yang digunakan untuk gerakan. Dia kemudian memberitahukan sesuai / bagian-bagian ini.
Pengikat penyaji
Ikatan ini adalah tautan antara Flutter Engine dan Render Tree . Dia bertanggung jawab untuk:
- mendengarkan peristiwa yang dihasilkan oleh mesin untuk menginformasikan tentang perubahan yang diterapkan oleh pengguna melalui pengaturan perangkat yang memengaruhi efek visual dan / atau semantik
- pesan ke mesin tentang perubahan yang akan diterapkan pada layar
Untuk memberikan perubahan yang akan ditampilkan di layar, RendererBinding bertanggung jawab untuk mengelola PipelineOwner dan menginisialisasi RenderView .
PipelineOwner adalah sejenis orkestra yang tahu apa yang perlu dilakukan dengan RenderObject sesuai dengan komponennya , dan mengoordinasikan tindakan ini.
Penjilidan ini mendengarkan perubahan yang diterapkan oleh pengguna melalui pengaturan perangkat yang memengaruhi bahasa (= lokal ) dan semantik .
Catatan kecil
Saya berasumsi bahwa pada tahap selanjutnya dalam pengembangan Flutter, semua acara yang berhubungan dengan semantik akan ditransfer ke SemanticsBinding , tetapi pada saat penulisan ini, ini tidak terjadi.
Selain itu, WidgetsBinding adalah tautan antara widget dan Flutter Engine . Dia bertanggung jawab untuk:
- manajemen proses pemrosesan perubahan struktur widget
- membuat panggilan
Pemrosesan perubahan pada struktur widget dilakukan menggunakan BuildOwner .
BuildOwner melacak widget mana yang perlu dibangun kembali, dan menangani tugas-tugas lain yang berlaku untuk struktur widget secara keseluruhan.
Bagian 2. Dari widget ke piksel
Sekarang kita telah mempelajari dasar-dasar pekerjaan internal Flutter , sekarang saatnya untuk berbicara tentang widget.
Dalam semua dokumentasi Flutter Anda akan membaca bahwa semua Widget (widget).
Ini hampir benar. Tetapi agar lebih tepat, saya lebih suka mengatakan:
Dari sisi pengembang, semua yang terkait dengan antarmuka pengguna dalam hal tata letak dan interaksi dilakukan menggunakan widget.
Mengapa begitu akurat? Selain kenyataan bahwa Widget memungkinkan pengembang untuk menentukan bagian dari layar dalam hal ukuran, konten, tata letak dan interaksi, TETAPI ada lebih banyak untuk itu. Jadi apa sebenarnya Widget itu ?
Konfigurasi Abadi
Jika Anda melihat kode sumber Flutter , Anda akan melihat definisi berikut dari kelas Widget .
@immutable abstract class Widget extends DiagnosticableTree { const Widget({ this.key }); final Key key; ... }
Apa artinya ini?
Anotasi "@immutable" sangat penting dan memberi tahu kami bahwa variabel apa pun di kelas Widget harus FINAL , dengan kata lain: "didefinisikan dan ditetapkan SEKALI UNTUK SEMUA ORANG ." Dengan demikian, setelah membuat sebuah instance, Widget tidak akan lagi dapat mengubah variabel internalnya.
Karena Widget tidak dapat diubah, ini dapat dianggap sebagai konfigurasi statis.
Struktur hierarkis widget
Saat Anda mendesain dengan Flutter, Anda menentukan struktur layar Anda menggunakan widget seperti ini:
Widget build(BuildContext context){ return SafeArea( child: Scaffold( appBar: AppBar( title: Text('My title'), ), body: Container( child: Center( child: Text('Centered Text'), ), ), ), ); }
Contoh ini menggunakan 7 widget yang bersama-sama membentuk struktur hierarkis. Skema yang sangat disederhanakan berdasarkan kode ini adalah sebagai berikut:

Seperti yang Anda lihat, diagram yang disajikan terlihat seperti pohon, di mana SafeArea adalah akarnya.
Hutan di belakang pohon
Seperti yang sudah Anda ketahui, widget itu sendiri bisa menjadi agregasi dari widget lain. Sebagai contoh, Anda dapat mengubah kode sebelumnya sebagai berikut:
Widget build(BuildContext context){ return MyOwnWidget(); }
Opsi ini mengasumsikan bahwa widget "MyOwnWidget" itu sendiri akan menampilkan SafeArea , Scaffold . Tetapi hal yang paling penting dalam contoh ini adalah itu
Widget dapat mewakili daun, simpul di pohon, bahkan pohon itu sendiri atau, mengapa tidak, hutan pohon ...
Memahami Elemen dalam Pohon
Apa hubungannya ini dengan itu?
Seperti yang akan ditampilkan nanti, untuk dapat menghasilkan piksel yang membentuk gambar yang ditampilkan pada perangkat, Flutter harus mengetahui secara rinci semua bagian kecil yang membentuk layar, dan untuk menentukan semua bagian, perlu diketahui perluasan semua widget.
Untuk mengilustrasikan hal ini, pertimbangkan prinsip boneka bersarang: ketika ditutup, Anda hanya melihat 1 boneka, tetapi mengandung satu boneka lain, yang pada gilirannya berisi boneka lain dan seterusnya ...

Ketika Flutter memperluas semua widget (bagian dari layar) , itu akan seperti mendapatkan semua boneka (bagian dari keseluruhan) .
Gambar di bawah ini menunjukkan bagian dari struktur hierarki terakhir widget yang sesuai dengan kode sebelumnya. Dalam warna kuning, saya menyoroti widget yang disebutkan dalam kode sebelumnya, sehingga Anda dapat mendefinisikannya di pohon akhir.

Klarifikasi penting
Bahasa "Pohon widget" hanya ada untuk memudahkan pemahaman, karena programmer menggunakan widget, tetapi tidak ada pohon widget di Flutter!
Bahkan, akan lebih tepat untuk mengatakan "pohon Elemen"
Sudah waktunya untuk memperkenalkan konsep Elemen .
Setiap widget memiliki satu elemen. Elemen-elemen terhubung satu sama lain dan membentuk pohon. Oleh karena itu, elemen adalah referensi ke sesuatu di pohon.
Untuk mulai dengan, pikirkan elemen sebagai simpul yang memiliki orang tua dan mungkin anak. Dengan menghubungkan mereka bersama melalui hubungan orangtua-anak , kita mendapatkan struktur pohon.

Seperti yang Anda lihat, elemen menunjuk ke satu widget, dan juga dapat menunjuk ke sebuah RenderObject .
Bahkan lebih baik ... Elemen menunjuk ke Widget yang membuat Elemen ini!
Mari kita simpulkan:
- Tidak ada pohon widget, tetapi ada pohon elemen
- Elemen dibuat oleh widget.
- Item merujuk ke widget yang membuatnya.
- Elemen yang ditautkan dengan hubungan orang tua
- Item mungkin memiliki "bayi."
- Elemen juga bisa mengarah ke RenderObject.
Elemen menentukan bagaimana bagian dari blok yang ditampilkan saling berhubungan satu sama lain.
Untuk lebih membayangkan di mana konsep elemen cocok, mari kita lihat representasi visual berikut:

Seperti yang Anda lihat, elemen tree adalah hubungan aktual antara widget dan RenderObjects .
Tapi mengapa Widget membuat Elemen ?
3 kategori widget
Di Flutter, widget dibagi menjadi 3 kategori, saya pribadi menyebutnya sebagai berikut (tapi ini hanya cara saya mengklasifikasikannya) :
Proksi
Tugas utama widget ini adalah menyimpan beberapa informasi (yang harus dapat diakses oleh widget), bagian dari struktur pohon berdasarkan Proxy. Contoh widget tersebut adalah InheritedWidget atau LayoutId .
Widget ini tidak secara langsung berpartisipasi dalam pembentukan antarmuka pengguna, tetapi digunakan untuk memperoleh informasi yang dapat mereka berikan.
Renderer
Widget ini secara langsung terkait dengan tata letak layar, karena mereka menentukan (atau digunakan untuk menentukan) ukuran , posisi , render . Contoh umum adalah: Baris , Kolom , Tumpukan , serta Padding , Align , Opacity , RawImage ...
Komponen
Ini adalah widget lain yang menyediakan secara langsung bukan informasi final terkait dengan ukuran, posisi, penampilan, melainkan data (atau kiat) yang akan digunakan untuk mendapatkan informasi yang paling final. Widget ini biasanya disebut sebagai komponen.
Contoh: RaisedButton , Scaffold , Text , GestureDetector , Container ...

File PDF ini mencantumkan sebagian besar widget yang dikelompokkan berdasarkan kategori.
Mengapa pemisahan ini penting? Karena tergantung pada kategori widget, jenis elemen yang terkait dikaitkan dengan ...
Jenis Barang
Ada beberapa jenis elemen:

Seperti yang Anda lihat pada gambar di atas, elemen-elemen dibagi menjadi 2 jenis utama:
Hebat! Begitu banyak informasi, tetapi bagaimana semua ini terkait satu sama lain dan mengapa menarik untuk membicarakannya?
Bagaimana widget dan elemen bekerja bersama
Dalam Flutter, semua mekanisme didasarkan pada pembatalan suatu elemen atau renderObject.
Pembatalan elemen dapat dilakukan dengan cara-cara berikut:
- menggunakan
setState
, yang membatalkan seluruh StatefulElement (perhatikan bahwa saya sengaja tidak mengatakan StatefulWidget ) - melalui pemberitahuan yang diproses oleh proxyElement (misalnya, InheritedWidget), yang membatalkan elemen apa pun yang bergantung pada proxyElement ini
Hasil dari pembatalan adalah bahwa tautan ke elemen yang sesuai muncul di daftar elemen kotor .
Pembatalan renderObject berarti bahwa struktur elemen tidak berubah sama sekali, tetapi ada perubahan di tingkat renderObject , misalnya:
- mengubah ukuran, posisi, geometri ...
- sesuatu perlu dicat ulang, misalnya, ketika Anda baru saja mengubah warna latar belakang, gaya font ...
Hasil dari pembatalan tersebut adalah tautan ke renderObject yang sesuai dalam daftar objek render (renderObjects) yang perlu dibangun kembali atau dicat ulang.
Terlepas dari jenis invalidation, SchedulerBinding disebut (ingat ini?) Untuk meminta Mesin Flutter menjadwalkan frame baru.
Inilah saat ketika Mesin Flutter "membangunkan" Penjadwal Penjilidan dan semua keajaiban terjadi ...
onDrawFrame ()
Sebelumnya dalam artikel ini, kami mencatat bahwa SchedulerBinding memiliki dua tanggung jawab utama, salah satunya adalah kesiapannya untuk menangani permintaan yang dibuat oleh Flutter Engine terkait dengan pembangunan kembali bingkai. Ini adalah saat yang tepat untuk fokus pada hal ini.
Diagram urutan parsial di bawah ini menunjukkan apa yang terjadi ketika SchedulerBinding menerima permintaan onDrawFrame () dari Flutter Engine .

Langkah 1. Elemen
WidgetsBinding disebut , dan pengikatan ini pertama kali mempertimbangkan perubahan yang terkait dengan elemen. WidgetsBinding memanggil metode buildScope dari objek buildOwner , karena BuildOwner bertanggung jawab untuk memproses pohon item. Metode ini melewati daftar elemen kotor dan meminta mereka membangun kembali .
Prinsip-prinsip utama dari metode rebuild()
ini ( rebuild()
) adalah:
- Ada permintaan untuk membangun kembali elemen (ini akan menghabiskan sebagian besar waktu), memanggil metode
build()
dari widget yang mengacu pada elemen ini (= Widget build (BuildContext context) {...}
metode). Metode build()
ini akan mengembalikan widget baru - Jika elemen tidak memiliki "anak-anak," maka elemen dibuat untuk widget baru (lihat di bawah) ( catatan: inflateWidget ), jika tidak
- widget baru dibandingkan dengan yang direferensikan oleh anak elemen
- Jika dapat dipertukarkan (= jenis dan kunci widget yang sama ), maka pembaruan terjadi dan anak disimpan.
- Jika tidak dapat dipertukarkan, maka anak tersebut dibuang ( ~ dibuang ) dan sebuah elemen dibuat untuk widget baru
- Item baru ini dipasang sebagai anak dari item tersebut. ( terpasang) = dimasukkan ke dalam elemen tree)
Animasi berikut akan mencoba membuat penjelasan ini sedikit lebih jelas.

Catatan tentang widget dan elemen
Untuk widget baru, elemen tipe tertentu dibuat yang sesuai dengan kategori widget, yaitu:
- InheritedWidget -> InheritedElement
- StatefulWidget -> StatefulElement
- StatelessWidget -> StatelessElement
- InheritedModel -> InheritedModelElement
- InheritedNotifier -> InheritedNotifierElement
- LeafRenderObjectWidget -> LeafRenderObjectElement
- SingleChildRenderObjectWidget -> SingleChildRenderObjectElement
- MultiChildRenderObjectWidget -> MultiChildRenderObjectElement
- ParentDataWidget -> ParentDataElement
Masing-masing tipe elemen ini memiliki perilaku masing-masing. Sebagai contoh:
- StatefulElement akan memanggil metode
widget.createState()
pada inisialisasi, yang akan membuat Negara dan mengaitkannya dengan elemen - Ketika elemen tipe RenderObjectElement dipasang, itu membuat RenderObject . RenderObject ini akan ditambahkan ke Render Tree dan dikaitkan dengan elemen.
Langkah 2. renderObjects
Sekarang setelah menyelesaikan semua tindakan yang terkait dengan elemen kotor , Pohon Elemen stabil. Jadi sudah waktunya untuk mempertimbangkan proses visualisasi.
Karena RendererBinding bertanggung jawab untuk merender Render Tree , WidgetsBinding memanggil metode drawFrame
RendererBinding .
Diagram parsial di bawah ini menunjukkan urutan tindakan yang dilakukan selama permintaan drawFrame () .

Pada langkah ini, tindakan berikut dilakukan:
- Setiap renderObject yang ditandai sebagai kotor diminta untuk menyusunnya (mis., Menghitung ukuran dan geometrinya)
- Setiap renderObject ditandai sebagai "perlu redrawing" digambar ulang menggunakan metode lapisan sendiri
- Adegan yang dihasilkan terbentuk dan dikirim ke Flutter Engine , sehingga yang terakhir mentransfernya ke layar perangkat
- Akhirnya, semantik juga diperbarui dan dikirim ke Flutter Engine
Di akhir alur kerja ini, layar perangkat disegarkan.
Bagian 3: Menangani Gerakan
Gerakan (= peristiwa yang berkaitan dengan aksi jari pada kaca ) diproses menggunakan GestureBinding .
Ketika Flutter Engine mengirim informasi tentang peristiwa gerakan melalui jendela.onPointerDataPacket API, GestureBinding menyadapnya, melakukan beberapa buffering, dan:
- mengonversi koordinat yang diberikan oleh Mesin Flutter agar sesuai dengan rasio piksel perangkat , lalu
- mengambil dari render, Melihat daftar semua objek Render yang ada di bagian layar yang terkait dengan koordinat acara
- kemudian beralih melalui daftar renderObjects yang dihasilkan dan mengirimkan acara terkait ke masing-masing
- jika renderObject "mendengarkan" untuk kejadian seperti ini, maka ia memprosesnya
Semoga sekarang saya mengerti betapa pentingnya renderObjects .
Bagian 4: Animasi
Bagian artikel ini adalah tentang konsep animasi dan pemahaman mendalam tentang Ticker .
Saat Anda bekerja dengan animasi, Anda biasanya menggunakan AnimationController atau widget apa pun untuk animasi ( catatan: AnimatedCrossFade ).
Di Flutter, semua yang terkait dengan animasi merujuk ke Ticker . Ticker , ketika aktif, hanya memiliki satu tugas: "ia meminta SchedulerBinding untuk mendaftarkan panggilan balik dan memberi tahu Flutter Engine untuk membangunkannya ketika panggilan balik baru muncul." Ketika Mesin Flutter siap, ia memanggil Penjadwal melalui permintaan: " onBeginFrame ". SchedulerBinding mengakses daftar panggilan balik ticker dan mengeksekusi masing-masing.
Setiap centang dicegat oleh pengontrol "tertarik" untuk memprosesnya. Jika animasinya selesai, maka ticker “nonaktif”, jika tidak ticker meminta Penjadwal untuk menjadwalkan panggilan balik baru. Dan seterusnya ...
Gambar penuh
Sekarang kita telah belajar bagaimana Flutter bekerja:

Buildcontext
Akhirnya, kembali ke diagram yang menunjukkan berbagai jenis elemen, dan perhatikan tanda tangan Elemen root:
abstract class Element extends DiagnosticableTree implements BuildContext { ... }
Kami melihat BuildContext yang sangat terkenal! Tapi apa itu?
BuildContext adalah antarmuka yang mendefinisikan sejumlah getter dan metode yang dapat diimplementasikan oleh suatu elemen. Kebanyakan BuildContext digunakan dalam metode build()
dari StatelessWidget atau State for StatefulWidget .
BuildContext tidak lain adalah Elemen itu sendiri, yang cocok
- widget sedang diperbarui (di dalam metode
build
atau builder
) - StatefulWidget dikaitkan dengan Status tempat Anda mereferensikan variabel konteks.
Ini berarti bahwa sebagian besar pengembang terus bekerja dengan elemen tanpa menyadarinya.
BuildContext?
BuildContext , , , BuildContext , :
- RenderObject , (, Renderer , -)
- RenderObject
- . ,
of
(, MediaQuery.of(context)
, Theme.of(context)
…)
, , BuildContext – , . StatelessWidget , StatefulWidget , setState()
, BuildContext .
, !
– , StatelessWidget .
, , StatefulWidget .
void main(){ runApp(MaterialApp(home: TestPage(),)); } class TestPage extends StatelessWidget {
, setState()
, : _element.markNeedsBuild()
.
Kesimpulan
: " ". , , Flutter , , , , . , , Widget , Element , BuildContext , RenderObject , . , .
. .
PS , () .
PSS Flutter internals Didier Boelens, )