Chuyển đến nội dung chính

Bài đăng

Hiển thị các bài đăng có nhãn DevTools

DevTools Network and Memory views you should actually use — hướng dẫn Flutter

Most production fires are leaks or chatty APIs. DevTools finds both. Bài này chuyển quan sát đó thành một mô hình nhỏ để bạn có thể kiểm thử, đo lường và giữ cho code dễ bảo trì khi app lớn lên. Vấn đề cốt lõi Finding leaked images and chatty APIs in ten minutes. Câu hỏi hữu ích không phải API hay pattern có đẹp riêng lẻ hay không, mà là state nằm ở đâu, boundary nào chịu trách nhiệm khi lỗi xảy ra, và người dùng phục hồi thế nào khi happy path biến mất. Mô hình thực tế Snapshot memory before and after a navigation loop. Hãy bắt đầu bằng một owner rõ ràng cho behavior. Widget chỉ nên render và phát intent; IO, persistence, permission và retry nên nằm sau một interface nhỏ. Nhờ vậy bạn có seam để fake trong test và một chỗ ghi lại các dữ kiện cần theo dõi ở production. Trong app Flutter, boundary thường có dạng: Widget phát intent như load, submit, refresh hoặc retry. Controller hoặc use case validate intent rồi gọi boundary. Boundary trả về data có kiểu hoặc failure có kiểu,...

DevTools Network and Memory views you should actually use

Most production fires are leaks or chatty APIs. DevTools finds both. This article turns that observation into a small implementation model you can test, measure, and keep boring when the app grows. The problem in one sentence Finding leaked images and chatty APIs in ten minutes. The useful question is not whether the API or pattern looks elegant in isolation. It is where state lives, which boundary owns failure, and how a user recovers when the happy path disappears. A practical model Snapshot memory before and after a navigation loop. Start with one explicit owner for the behavior. Keep widgets responsible for rendering and user intent; keep IO, persistence, permissions, and retries behind a small interface. That gives you a seam for a fake in tests and a place to record the facts that matter in production. For a Flutter app, the boundary usually looks like this: The widget emits an intent such as load, submit, refresh, or retry. A controller or use case validates the intent...

Flutter Property Editor: inspect widgets without print debugging — hướng dẫn Flutter

Property Editor exposes editable fields for the selected widget in DevTools. Bài này chuyển quan sát đó thành một mô hình nhỏ để bạn có thể kiểm thử, đo lường và giữ cho code dễ bảo trì khi app lớn lên. Vấn đề cốt lõi Edit properties live from DevTools while iterating on a screen. Câu hỏi hữu ích không phải API hay pattern có đẹp riêng lẻ hay không, mà là state nằm ở đâu, boundary nào chịu trách nhiệm khi lỗi xảy ra, và người dùng phục hồi thế nào khi happy path biến mất. Mô hình thực tế Faster than hot-reload cycles when tuning padding, colors, and flags. Hãy bắt đầu bằng một owner rõ ràng cho behavior. Widget chỉ nên render và phát intent; IO, persistence, permission và retry nên nằm sau một interface nhỏ. Nhờ vậy bạn có seam để fake trong test và một chỗ ghi lại các dữ kiện cần theo dõi ở production. Trong app Flutter, boundary thường có dạng: Widget phát intent như load, submit, refresh hoặc retry. Controller hoặc use case validate intent rồi gọi boundary. Boundary trả v...

Tìm rò rỉ bộ nhớ trong Flutter: năm loại đối tượng không bao giờ được dispose

Rò rỉ bộ nhớ trong Flutter hiếm khi tự khai báo. Ứng dụng chạy được, test xanh, rồi ai đó chuyển qua lại giữa hai màn hình bốn mươi lần và tiến trình đứng ở mức 900 MB. Trên một máy Android tầm trung, kết cục là bị hệ thống giết vì hết bộ nhớ, và bạn nhận được báo cáo “app tự đóng” mà không có stack trace nào. Dart có bộ thu gom rác, nên rò rỉ ở đây chỉ có đúng một nghĩa: vẫn còn thứ gì đó giữ tham chiếu tới một đối tượng bạn đã dùng xong . Toàn bộ cuộc điều tra là đi tìm cái “thứ gì đó” ấy. Năm mô-típ Trên thực tế, gần như mọi vụ rò rỉ tôi từng truy trong ứng dụng Flutter đều thuộc một trong số này. 1. Controller không bao giờ được dispose. AnimationController , TextEditingController , ScrollController , TabController , PageController — cái nào cũng giữ listener và, với trường hợp animation, còn giữ một ticker đã đăng ký với bộ lập lịch. class _EditorState extends State < Editor > with SingleTickerProviderStateMixin { late final _text = TextEditingController ()...

Vì sao ListView của bạn chậm, và bốn cách sửa thật sự có tác dụng

Đội Flutter nào cũng gặp chuyện này. Danh sách chạy ngon với hai mươi mục lúc phát triển, phát hành, rồi một người dùng có tám trăm mục đã lưu báo rằng cuộn bị khựng và ứng dụng cảm giác nặng nề. Phản xạ đầu tiên là đổ lỗi cho ListView , cho Flutter, hoặc cho cái máy. ListView không có lỗi. Trong mọi danh sách chậm tôi từng phân tích, nguyên nhân là một trong bốn thứ, và phân biệt chúng mất khoảng mười phút. Trước tiên: xem luồng nào đang trễ Trước khi đổi bất cứ thứ gì, hãy chạy ở chế độ profile trên thiết bị thật và mở performance view của DevTools. Mỗi frame được vẽ thành hai thanh: Luồng UI dài → build và layout đang đắt. itemBuilder của bạn làm quá nhiều việc. Luồng raster dài → vẽ đang đắt. Bóng đổ, làm mờ, lớp opacity, saveLayer, ảnh lớn. Phân biệt đó loại bỏ ngay một nửa số cách sửa khả dĩ. Thêm RepaintBoundary vào một danh sách mà nút thắt nằm ở luồng UI chẳng có tác dụng gì; đơn giản hoá cấu trúc widget trong một danh sách mà luồng raster đang bão hoà vì Backdro...

Flutter cold start: measuring the time before your first frame

“The app takes three seconds to open” is a complaint, not a measurement. Three seconds from what — the tap, the process spawning, the engine coming up, or the moment your main() runs? Each of those is a different problem with a different fix, and optimising the wrong one is how teams spend a sprint moving startup from 2.9 s to 2.8 s. Cold start in a Flutter app has four phases, and they are separable. The four phases 1. Process launch. The OS creates the process, loads the executable and its shared libraries, and hands control to the platform runner. Nothing in your Dart code affects this. What does affect it is binary size (see the app size discussion) and, on Android, the number of libraries to link. 2. Engine initialisation. The Flutter engine starts, the Dart VM comes up, and — in release builds — the AOT snapshot is mapped in. Plugin registration happens on the platform side here. 3. Dart main() to runApp() . Your code. This is the phase you control completely, and the o...

Flutter Property Editor: inspect widgets without print debugging

Property Editor exposes editable fields for the selected widget in DevTools. This article turns that observation into a small implementation model you can test, measure, and keep boring when the app grows. The problem in one sentence Edit properties live from DevTools while iterating on a screen. The useful question is not whether the API or pattern looks elegant in isolation. It is where state lives, which boundary owns failure, and how a user recovers when the happy path disappears. A practical model Faster than hot-reload cycles when tuning padding, colors, and flags. Start with one explicit owner for the behavior. Keep widgets responsible for rendering and user intent; keep IO, persistence, permissions, and retries behind a small interface. That gives you a seam for a fake in tests and a place to record the facts that matter in production. For a Flutter app, the boundary usually looks like this: The widget emits an intent such as load, submit, refresh, or retry. A control...

DevTools Network and Memory views you should actually use — hướng dẫn Flutter

Most production fires are leaks or chatty APIs. DevTools finds both. Bài này chuyển quan sát đó thành một mô hình nhỏ để bạn có thể kiểm thử, đo lường và giữ cho code dễ bảo trì khi app lớn lên. Vấn đề cốt lõi Finding leaked images and chatty APIs in ten minutes. Câu hỏi hữu ích không phải API hay pattern có đẹp riêng lẻ hay không, mà là state nằm ở đâu, boundary nào chịu trách nhiệm khi lỗi xảy ra, và người dùng phục hồi thế nào khi happy path biến mất. Mô hình thực tế Snapshot memory before and after a navigation loop. Hãy bắt đầu bằng một owner rõ ràng cho behavior. Widget chỉ nên render và phát intent; IO, persistence, permission và retry nên nằm sau một interface nhỏ. Nhờ vậy bạn có seam để fake trong test và một chỗ ghi lại các dữ kiện cần theo dõi ở production. Trong app Flutter, boundary thường có dạng: Widget phát intent như load, submit, refresh hoặc retry. Controller hoặc use case validate intent rồi gọi boundary. Boundary trả về data có kiểu hoặc failure có kiểu,...

DevTools Network and Memory views you should actually use

Most production fires are leaks or chatty APIs. DevTools finds both. This article turns that observation into a small implementation model you can test, measure, and keep boring when the app grows. The problem in one sentence Finding leaked images and chatty APIs in ten minutes. The useful question is not whether the API or pattern looks elegant in isolation. It is where state lives, which boundary owns failure, and how a user recovers when the happy path disappears. A practical model Snapshot memory before and after a navigation loop. Start with one explicit owner for the behavior. Keep widgets responsible for rendering and user intent; keep IO, persistence, permissions, and retries behind a small interface. That gives you a seam for a fake in tests and a place to record the facts that matter in production. For a Flutter app, the boundary usually looks like this: The widget emits an intent such as load, submit, refresh, or retry. A controller or use case validates the intent...

Tìm rò rỉ bộ nhớ trong Flutter: năm loại đối tượng không bao giờ được dispose

Rò rỉ bộ nhớ trong Flutter hiếm khi tự khai báo. Ứng dụng chạy được, test xanh, rồi ai đó chuyển qua lại giữa hai màn hình bốn mươi lần và tiến trình đứng ở mức 900 MB. Trên một máy Android tầm trung, kết cục là bị hệ thống giết vì hết bộ nhớ, và bạn nhận được báo cáo “app tự đóng” mà không có stack trace nào. Dart có bộ thu gom rác, nên rò rỉ ở đây chỉ có đúng một nghĩa: vẫn còn thứ gì đó giữ tham chiếu tới một đối tượng bạn đã dùng xong . Toàn bộ cuộc điều tra là đi tìm cái “thứ gì đó” ấy. Năm mô-típ Trên thực tế, gần như mọi vụ rò rỉ tôi từng truy trong ứng dụng Flutter đều thuộc một trong số này. 1. Controller không bao giờ được dispose. AnimationController , TextEditingController , ScrollController , TabController , PageController — cái nào cũng giữ listener và, với trường hợp animation, còn giữ một ticker đã đăng ký với bộ lập lịch. class _EditorState extends State < Editor > with SingleTickerProviderStateMixin { late final _text = TextEditingController ()...

Vì sao ListView của bạn chậm, và bốn cách sửa thật sự có tác dụng

Đội Flutter nào cũng gặp chuyện này. Danh sách chạy ngon với hai mươi mục lúc phát triển, phát hành, rồi một người dùng có tám trăm mục đã lưu báo rằng cuộn bị khựng và ứng dụng cảm giác nặng nề. Phản xạ đầu tiên là đổ lỗi cho ListView , cho Flutter, hoặc cho cái máy. ListView không có lỗi. Trong mọi danh sách chậm tôi từng phân tích, nguyên nhân là một trong bốn thứ, và phân biệt chúng mất khoảng mười phút. Trước tiên: xem luồng nào đang trễ Trước khi đổi bất cứ thứ gì, hãy chạy ở chế độ profile trên thiết bị thật và mở performance view của DevTools. Mỗi frame được vẽ thành hai thanh: Luồng UI dài → build và layout đang đắt. itemBuilder của bạn làm quá nhiều việc. Luồng raster dài → vẽ đang đắt. Bóng đổ, làm mờ, lớp opacity, saveLayer, ảnh lớn. Phân biệt đó loại bỏ ngay một nửa số cách sửa khả dĩ. Thêm RepaintBoundary vào một danh sách mà nút thắt nằm ở luồng UI chẳng có tác dụng gì; đơn giản hoá cấu trúc widget trong một danh sách mà luồng raster đang bão hoà vì Backdro...