Vòng đời của một Stateful Widget trong Flutter là một quá trình phức tạp, với nhiều giai đoạn và các phương thức mà bạn có thể ghi đè để tùy chỉnh hành vi của widget. Nắm vững vòng đời này sẽ giúp bạn quản lý trạng thái và tài nguyên hiệu quả hơn trong ứng dụng của mình. Dưới đây là mô tả chi tiết về vòng đời của một Stateful Widget, cùng với ví dụ minh họa cụ thể cho từng giai đoạn.
1. Tạo và Cấu Hình Stateful Widget
Khi bạn tạo một Stateful Widget, phương thức createState()
sẽ được gọi. Đây là bước đầu tiên trong vòng đời của widget.
class MyStatefulWidget extends StatefulWidget {
@override
MyState createState() {
return MyState(); // Trả về đối tượng State tương ứng
}
}
- Phương thức
createState()
: Phương thức này chỉ được gọi một lần khi widget được tạo ra. Nó tạo ra một đối tượng State
, nơi bạn sẽ định nghĩa các biến trạng thái và logic của widget.
2. Vòng Đời của State
Sau khi phương thức createState()
được gọi, đối tượng State
sẽ trải qua các bước sau:
2.1. initState()
Đây là phương thức đầu tiên trong vòng đời của đối tượng State
, và nó được gọi ngay sau khi đối tượng State
được tạo.
class MyState extends State<MyStatefulWidget> {
int _counter = 0; // Biến trạng thái
@override
void initState() {
super.initState();
// Khởi tạo giá trị ban đầu cho biến
print("Widget được khởi tạo");
}
}
- Chức năng: Đây là nơi bạn thực hiện các khởi tạo cần thiết, như thiết lập giá trị ban đầu cho các biến trạng thái, hoặc bắt đầu các hoạt động không đồng bộ (như gọi API hoặc khởi tạo listener). Lưu ý rằng
initState()
chỉ được gọi một lần trong vòng đời của widget.
2.2. didChangeDependencies()
Sau khi initState()
được gọi, phương thức didChangeDependencies()
sẽ được gọi. Phương thức này được gọi mỗi khi có sự thay đổi trong các InheritedWidget
mà widget này phụ thuộc vào.
@override
void didChangeDependencies() {
super.didChangeDependencies();
// Xử lý các thay đổi về dependencies
print("Dependencies đã thay đổi");
}
- Chức năng: Thích hợp để thực hiện các thay đổi dựa trên context hoặc để thực hiện các hoạt động phụ thuộc vào các đối tượng
InheritedWidget
.
2.3. build(BuildContext context)
Phương thức build()
sẽ được gọi để xây dựng giao diện người dùng cho widget. Đây là một trong những phương thức quan trọng nhất trong vòng đời của widget.
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Vòng đời Stateful Widget")),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Số lần nhấn: $_counter'),
ElevatedButton(
onPressed: () {
setState(() {
_counter++; // Cập nhật trạng thái
});
},
child: Text('Tăng'),
),
],
),
),
);
}
- Chức năng: Phương thức này trả về một widget con (thường là một cây widget) và được gọi lại mỗi khi widget cần được vẽ lại, ví dụ như khi bạn gọi
setState()
.
2.4. setState(VoidCallback fn)
Phương thức setState()
được sử dụng để cập nhật trạng thái của widget. Khi được gọi, nó sẽ kích hoạt một chu kỳ xây dựng lại (rebuild).
void increaseCounter() {
setState(() {
_counter++; // Gọi setState để cập nhật số đếm
});
}
- Chức năng: Bất cứ khi nào bạn thay đổi trạng thái trong widget, bạn cần gọi
setState()
để Flutter biết rằng widget cần được tái xây dựng.
3. Thay Đổi Trạng Thái
Khi trạng thái của widget thay đổi thông qua setState()
, vòng đời sẽ trở lại với việc gọi phương thức build()
để cập nhật giao diện người dùng:
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Vòng đời Stateful Widget")),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Số lần nhấn: $_counter'),
ElevatedButton(
onPressed: increaseCounter, // Gọi phương thức tăng
child: Text('Tăng'),
),
],
),
),
);
}
- Chức năng: Phương thức
build()
sẽ được gọi lại mỗi khi có sự thay đổi trong trạng thái. Tại đây, widget sẽ được cập nhật giao diện dựa trên trạng thái hiện tại.
4. Kết Thúc Vòng Đời
Khi widget không còn được sử dụng và cần giải phóng tài nguyên, các phương thức sau sẽ được gọi:
4.1. deactivate()
Phương thức deactivate()
sẽ được gọi khi widget bị loại bỏ khỏi cây widget nhưng vẫn còn ở trong bộ nhớ.
@override
void deactivate() {
super.deactivate();
print("Widget đã bị loại bỏ khỏi cây widget");
}
- Chức năng: Đây là thời điểm tốt để thực hiện các công việc dọn dẹp tạm thời, như hủy đăng ký các listener mà bạn đã thiết lập.
4.2. dispose()
Cuối cùng, phương thức dispose()
sẽ được gọi ngay trước khi đối tượng State
bị hủy. Đây là nơi bạn nên giải phóng các tài nguyên mà bạn đã tạo trong initState()
.
@override
void dispose() {
// Giải phóng tài nguyên nếu cần
print("Giải phóng tài nguyên");
super.dispose();
}
- Chức năng: Bạn nên giải phóng các tài nguyên như các listener, animation controllers, hoặc các đối tượng khác mà bạn đã tạo trong
initState()
. Sau khi gọi dispose()
, đối tượng State
sẽ không còn tồn tại.
Tóm Tắt Vòng Đời của Stateful Widget
Vòng đời của một Stateful Widget trong Flutter có thể được tóm tắt theo thứ tự sau:
- Tạo:
createState()
- Khởi tạo:
initState()
- Phụ thuộc thay đổi:
didChangeDependencies()
- Xây dựng giao diện:
build()
- Cập nhật trạng thái:
setState() → build()
- Giải phóng tài nguyên:
deactivate()
, dispose()
Kết Luận
Việc hiểu rõ về vòng đời của một Stateful Widget trong Flutter giúp bạn quản lý trạng thái và tài nguyên hiệu quả hơn trong ứng dụng của mình. Mỗi phương thức trong vòng đời này có một vai trò quan trọng và biết cách sử dụng chúng sẽ giúp bạn tối ưu hóa ứng dụng, cải thiện hiệu suất và trải nghiệm người dùng. Hãy luôn chú ý đến việc dọn dẹp tài nguyên và trạng thái để tránh các vấn đề về hiệu suất và bộ nhớ trong ứng dụng của bạn.