Học Flutter cơ bản đến nâng cao không khó! Để 200Lab Blog cập nhật cho bạn những thông tin mới nhất về Widget Tree, Element Tree và Render Tree nhé.
Khi đọc qua các bài trước, bạn có thể tự hỏi về cách rebuild các widget cơ bản trong Flutter. Mỗi widget đều ẩn chứa một hàm build riêng, và việc gọi nó diễn ra liên tục! Trong quá trình này, liệu chúng ta sẽ tiêu tốn bao nhiêu % hiệu suất quý báu?
Để khám phá câu trả lời, hãy bắt đầu với Element Tree, Widget Tree và Render Tree. Hãy cùng hiểu cách Flutter thực thi phương thức build(){...}
, cách nó tái xây dựng và thay đổi dữ liệu trên màn hình.
Hiểu biết về cách Flutter thực thi việc tái xây dựng và thay đổi thông tin trên màn hình, bạn sẽ không chỉ tiết kiệm thời gian mà còn tối ưu hóa hiệu suất ứng dụng của mình.
Flutter cơ bản - Những điều bạn cần biết
Flutter không vẽ lại hay tạo lại toàn bộ giao diện người dùng mỗi khi ta phương thức build(){...}
được gọi. Chúng ta sẽ thảo luận chi tiết hơn về vấn đề này.
- Flutter cố gắng đáp ứng để ứng dụng chạy ở 60 FPS (Frames Per Second). Vì vậy, nó cập nhật màn hình 60 lần mỗi giây. Có nghĩa là màn hình được Flutter repaint lại 60 lần mỗi giây. Điều này khác dễ hiểu vì tất cả các ứng dụng và trò chơi chạy ở tốc độ 60 FPS trở lên theo mặc định.
- Điều này sẽ chỉ trở nên kém hiệu quả nếu Flutter cứ phải tính toán lại toàn bộ bố cục 60 lần mỗi giây!
- Nếu Flutter vẽ thứ gì đó lên màn hình lần đầu tiên, nó cần tính toán ra vị trí, màu sắc, văn bản, v.v. của mọi phần tử trên màn hình. Tóm lại, trong lần kết xuất giao diện đầu tiên, Flutter cần chỉnh sửa từng điểm ảnh trên màn hình.
- Đối với các lần sửa/vẽ tiếp theo, để làm mới giao diện người dùng nếu không có gì thay đổi thì Flutter sẽ lấy thông tin cũ mà nó đã có từ trước đó và vẽ thông tin đó lên màn hình siêu nhanh và rất hiệu quả.
- Từ đó, tốc độ vẽ lại không phải là vấn đề, sẽ chỉ là vấn đề nếu Flutter phải tính toán lại mọi thứ trên màn hình với mỗi lần làm mới mà thôi.
- Đây là những gì chúng ta sẽ thảo luận chi tiết ở bài viết này: liệu Flutter có tính toán lại mọi thứ mỗi khi phương thức
build(){...}
được gọi hay không?!
Widget Tree của Flutter
- Widget Tree chỉ đơn giản là tất cả các Widget mà bạn đang dùng để xây dựng ứng dụng, tức là code mà bạn viết sẽ tạo nên widget tree.
- Nó hoàn toàn do bạn kiểm soát. Bạn khai báo các widget lồng ghép chúng lại với nhau để tạo nên bố cục mong muốn.
- Cái Tree này được xây dựng bởi Flutter khi call phương thức
build(){...}
từ code của chúng ta, chúng chỉ là một loạt các cài đặt cấu hình mà Flutter sẽ xử lý. - Nó không chỉ đơn giản xuất hiện ra trên màn hình rồi thôi. Thay vào đó, nó sẽ cho Flutter biết những gì sẽ vẽ lên màn hình ở lần tiếp theo. Widget tree được rebuild rất thường xuyên.
Element Tree trong Flutter
- Element Tree liên kết vào Widget Tree, là thông tin được thiết lập với các đối tượng/phần tử thực sự được hiển thị. Nó rất hiếm khi rebuild.
- Element Tree được quản lý theo một cách khác và sẽ không rebuild khi phương thức
build(){...}
được gọi. - Ở mỗi Widget trong Widget Tree, Flutter sẽ tự động tạo một element cho nó. Nó được thực hiện ngay khi Flutter xử lý Widget ở lần đầu tiên.
- Ở đây chúng ta có thể nói rằng một element là một đối tượng được quản lý trong bộ nhớ bởi Flutter, nó có liên quan đến Widget trong Widget Tree.
- Element chỉ giữ một tham chiếu tới Widget (trong Widget Tree) đang giữ các thông số giao diện đầu cuối .
Khi Flutter nhìn thấy stateful widget, nó sẽ tạo element và sau đó cũng gọi phương thứccreateState()
để tạo một state object mới dựa trên state class.
Do đó, state là một đối tượng độc lập trong một Stateful Widget được kết nối với cả hai là element trong Element Tree và Widget trong Widget Tree.
Render Tree trong Flutter
- Render Tree đại diện của các element/đối tượng thực sự được hiển thị trên màn hình.
- Render Tree cũng không rebuild thường xuyên!
- Element Tree cũng được liên kết với Render Tree. Element trong Element Tree trỏ đến render object mà chúng ta thực sự thấy trên màn hình.
- Bất cứ khi nào Flutter thấy một element chưa được render trước đó thì nó sẽ tham chiếu đến Widget trong Widget Tree để thiết lập, sau đó tạo một element trong element tree.
- Flutter cũng có một layout phase, giai đoạn mà nó tính toán và lấy không gian diện tích có sẵn trên màn hình, chiều, kích thước, hướng, v.v.
- Nó cũng có một phase khác để thiết lập các listeners với các Widget để chúng ta có thể thao tác các sự kiện, v.v.
Một cách đơn giản, chúng ta có thể thấy rằng phần tử chưa được render thì sẽ được render ra màn hình. Element (trong element tree) sau đó có có một con trỏ đến Render Object (trong Render Tree) trên màn hình. Nó cũng có một con trỏ tới Widget (trong Widget Tree) mang theo các thông tin cấu hình cho phần tử này.
Cách Flutter thực thi phương thức build(){...}
Phương thức build(){...}
được Flutter gọi bất cứ khi nào state thay đổi. Về cơ bản, có hai kích hoạt quan trọng có thể dẫn đến việc rebuild.
- Một là khi phương thức
setState(){...}
được gọi trong một Stateful Widget. Việc callsetState(){...}
khi được gọi tự động sẽ dẫn đến phương thứcbuild(){...}
được gọi ngay sau đó. - Thứ hai, bất cứ khi nào MediaQuery hoặc lệnh
Theme.of(...)
được gọi, bàn phím ảo xuất hiện hoặc biến mất, v.v. Bất cứ khi nào dữ liệu của những thứ này thay đổi, nó sẽ tự động kích hoạt phương thứcbuild(){...}
.
Chính xác là việc call setState(){...}
sẽ đánh dấu phần tử tương ứng là dirty
. Đối với lần render tiếp theo, diễn ra 60 lần mỗi giây, Flutter sau đó sẽ xem xét đến các thông tin thiết lập mới được tạo bởi phương thức build(){...} và sau đó cập nhật màn hình.
Tất cả các Widget lồng vào nhau bên trong Widget được đánh dấu là dirty sẽ được tạo các đối tượng mới widget/dart cho chúng. Do đó, một Widget Tree mới sẽ được tạo ra tương ứng các phiên bản mới của tất cả các Widget này.
Widget Tree mới được tạo vì Widget Tree là bất biến, tức là bạn không thể thay đổi thuộc tính của một Widget hiện có mà chỉ có thể ghi đè lên nó bằng một cái mới. Phương pháp này được Flutter thực thi rất nhiều do nó có thể phát hiện các thay đổi hiệu quả hơn khi một đối tượng thay đổi.
Ví dụ:
Chúng ta có một Stateful Widget được hiển thị trên màn hình. Nó có một Child Widget lồng vào một văn bản (Text Widget). Text widget là một Stateless Widget và hiển thị văn bản trên màn hình dựa trên state của parent widget của nó.
import 'package:flutter/material.dart';
class TestWidget extends StatefulWidget {
@override
_TestWidgetState createState() => _TestWidgetState();
}
class _TestWidgetState extends State<TestWidget> {
var state = true;
@override
Widget build(BuildContext context) {
return Container(
color: Colors.green,
child: GestureDetector(
onTap: () {
setState(() {
state = !state;
});
},
child: Text(state ? 'True' : 'False')),
);
}
}
Bạn có thể thấy rằng ngay khi state thay đổi, văn bản hiển thị sẽ chuyển từ True
sang False
và ngược lại. GestureDetector
là parent của Text Widget. Vì là parent của nó, GestureDetector xử lý sự thay đổi state bằng cách call phương thức setState () {...}
.
Ngay sau khi Text Widget được nhấn vào thì parent nó sẽ xử lý setState, tức là TestWidget được đánh dấu là dirty. Một Widget Tree mới được hình thành khi build method được gọi bởi Flutter.
Sau đó, thông tin Widget Tree mới được so sánh với nội dung thực tế đang được hiển thị trên màn hình. Flutter phát hiện rằng màu vùng chứa không thay đổi và chỉ văn bản bên trong Text Widget được thay đổi. Vì vậy, Render Tree sẽ không hoàn toàn hiển thị lại nội dung mà chỉ hiển thị văn bản bên trong Text Widget mà thôi.
Đây là lý do tại sao Flutter làm việc rất hiệu quả. Element Tree không cần rebuild khi phương thức build(){...}
được call. Chỉ Widget Tree được rebuild và sau đó Element Tree chỉ cập nhật tham chiếu của nó trỏ đến Widget Tree mới. Sau đó, nó sẽ kiểm tra xem thông tin mới của các Widget hiện có hay không. Nếu đúng như vậy thì nó sẽ chuyển thông tin vào các Render Object để các thay đổi có thể được vẽ trên màn hình.
Nếu bạn muốn đọc thêm về logic render thì mình nghĩ bạn nên xem bài viết này từ các tài liệu chính thức của Flutter.
Chú thích nhanh về các widget trong Flutter
Một số Widget sẽ không bao giờ thay đổi ngay cả khi rebuild Widget Tree nên bạn có thể tối ưu hóa quá trình build hơn. Bạn có thể sử dụng từ khóa const
phía trước chúng để cho Flutter biết rằng Widget nè sẽ không bao giờ thay đổi, do đó làm cho Flutter bỏ qua việc rebuild hoàn toàn widget đó. Ví dụ:
Padding(
padding: const EdgeInsets.all(8.0),
child: GestureDetector(
onTap: () {
setState(() {
state = !state;
});
},
child: Text(state ? 'True' : 'False')),
),
Ở trên, chúng ta chỉ định const
bỏ qua việc rebuild Padding Widget. Ngoài ra, bạn có thể tối ưu hóa quy trình xây dựng bằng cách tách các widget lớn hơn thành các widget nhỏ hơn một cách cẩn thận.
Kết luận về Flutter cơ bản: Widget Tree, Element Tree & Render Tree
Bài viết này đã cung cấp cho bạn thêm nhiều thông tin về Flutter cơ bản. Hy vọng bạn đã nhận ra sự hấp dẫn và ý nghĩa của việc tái xây dựng Widget.
Hãy áp dụng những kiến thức này vào thực tế, để bạn có trải nghiệm thực sự độc đáo. Tiếp tục tìm hiểu và đặt ra câu hỏi, bởi những chi tiết nhỏ thường ẩn chứa những khám phá lớn. Chúc bạn luôn luôn tận hưởng hành trình học hỏi của mình.
Bài viết được chuyển ngữ và biên tập lại từ Shashank Biplav.
Giờ thì bạn đã nắm chắc kiến thức về Flutter cơ bản cũng như cách hoạt động của các Widget trong Flutter rồi nhé!
Các Bài Viết Bạn Sẽ Thích:
Flutter cơ bản: Widget Tree, Element Tree và Render Tree
Flutter cơ bản: Lập trình ứng dụng đầu tiên
Flutter 3 - Những cập nhật mới có gì hot
Flutter Coding UI Speed Code
Flutter là gì? Vì sao nên học công cụ lập trình Flutter?
Chau Le
Cực thích đồ ngọt như sữa, kem. Thích phiêu lưu mạo hiểm nhưng vì Covid mà vô tình trở thành người chia sẻ nội dung lập trình :))
follow me :
Bài viết liên quan
Tự học Dart: Các Dart Operators (toán tử) bạn cần biết
Sep 02, 2023 • 18 min read
Flutter cơ bản: Điều cần biết khi lập trình ứng dụng đầu tiên
Aug 23, 2023 • 13 min read
Dart là gì? Giới thiệu cơ bản về ngôn ngữ lập trình Dart
Aug 21, 2023 • 11 min read
Flutter là gì? Vì sao nên học công cụ lập trình Flutter?
Aug 19, 2023 • 11 min read
So sánh StatelessWidget và StatefulWidget
Jul 17, 2022 • 12 min read
Tổng hợp các Shortcuts, Extensions & Settings trong VSCode khi lập trình Flutter
Jun 03, 2022 • 10 min read