ĐẠI HỌC QUỐC GIA THÀNH PHỐ HỒ CHÍ MINH
ĐẠI HỌC CÔNG NGHỆ THÔNG TIN
KHOA CÔNG NGHỆ PHẦN MỀM
MÔN: ĐỒ ÁN 2
SE122.L11.PMCL
BÁO CÁO ĐỒ ÁN CUỐI KÌ
Đề tài:
Tìm hiểu Flutter và xây dựng ứng dụng
minh họa
Giảng viên hướng dẫn: Nguyễn Tấn Toàn
Sinh viên thực hiện: 17521177 – Nguyễn Quốc Trung
TP. Hồ Chí Minh, tháng 1 năm 2021
LỜI CẢM ƠN
Đầu tiên, nhóm tác giả xin gởi lời cảm ơn chân thành đến tập thể quý Thầy
Cô Trường Đại học Công nghệ thông tin – Đại học Quốc gia TP.HCM và quý Thầy
Cô khoa Công nghệ phần mềm đã giúp cho em có những kiến thức cơ bản làm nền
tảng để thực hiện đề tài này.
Đặc biệt, em xin gửi lời cảm ơn và lòng biết ơn sâu sắc nhất tới Thầy Nguyễn
Tấn Toàn. Thầy đã trực tiếp hướng dẫn tận tình, sửa chữa và đóng góp nhiều ý kiến
giúp em hoàn thành tốt và đúng hạn báo cáo mơn học của mình.
Trong thời gian một học kỳ thực hiện đề tài, em đã vận dụng những kiến thức
nền tảng đã tích lũy đồng thời kết hợp với việc học hỏi và nghiên cứu những kiến
thức mới. Từ đó, em vận dụng tối đa những gì đã thu thập được để hoàn thành một
báo cáo đồ án tốt nhất. Tuy nhiên, trong q trình thực hiện, em khơng tránh khỏi
những thiếu sót. Chính vì vậy, em rất mong nhận được những sự góp ý từ phía các
Thầy Cơ nhằm hoàn thiện những kiến thức mà em đã học tập và là hành trang để
em thực hiện tiếp các đề tài khác trong tương lai.
Xin chân thành cảm ơn các quý Thầy Cô !
Sinh viên thực hiện
Nguyễn Quốc Trung
1
NHẬN XÉT CỦA GIẢNG VIÊN
.........................................................................................................................................................
.........................................................................................................................................................
.........................................................................................................................................................
.........................................................................................................................................................
.........................................................................................................................................................
.........................................................................................................................................................
.........................................................................................................................................................
.........................................................................................................................................................
.........................................................................................................................................................
.........................................................................................................................................................
.........................................................................................................................................................
.........................................................................................................................................................
.........................................................................................................................................................
.........................................................................................................................................................
.........................................................................................................................................................
.........................................................................................................................................................
.........................................................................................................................................................
.........................................................................................................................................................
.........................................................................................................................................................
.........................................................................................................................................................
.........................................................................................................................................................
.........................................................................................................................................................
.........................................................................................................................................................
.........................................................................................................................................................
.........................................................................................................................................................
.........................................................................................................................................................
.........................................................................................................................................................
.........................................................................................................................................................
2
Mục lục
A. Tìm hiểu về Flutter
I.
Tổng quan về Flutter
1. Nguồn gốc của Flutter………………………………………5
2. Tăng trưởng và Tập trung vào di động……………………...6
3. Sơ lược về Kiến trúc Flutter………………………………...7
4. Trải nghiệm của lập trình viên……………………………...10
a. Plugin và Package……………………………………….10
b. Sự quản lý……………………………………………….11
c. Lợi ích của Flutter………………………………………11
5. Điều gì đang làm các lập trình viên ngần ngại…………….12
6. So sánh Flutter và React Native…………………………...13
II. Tổng quan về Kiến trúc Flutter
1. Architectural layers………………………………………...14
2. Giao diện người dùng phản ứng……………………………16
3. Widgets…………………………………………………….18
a. Thành phần……………………………………………...18
b. Xây dựng Widget……………………………………….19
c. Widget state…………………………………………….20
d. Quản lý State……………………………………………21
4. Kết xuất và bố cục…………………………………………23
a. Mô hình kết xuất của Flutter……………………………23
b. Từ đầu vào của người dùng đến GPU………………….24
c. Xây dựng: từ Widget thành Element……………………24
d. Bố cục và kết xuất………………………………………25
5. Platform embedding……………………………………….28
6. Tích hợp với mã khác………………………………………29
a. Platform channels……………………………………….29
b. Foreign Function Interface………………………………30
c. Hiển thị các điều khiển gốc trong ứng dụng Flutter…….30
d. Lưu trữ nội dung Flutter trong ứng dụng mẹ……………31
7. Hỗ trợ web flutter………………………………………….32
3
B. Xây dựng ứng dụng minh họa
Ứng dụng chia sẻ hình ảnh trực tuyến Halogram
1. Thơng tin chung ……………………………………………… 34
2. Một số package hỗ trợ……………………………………….. 34
3. Chức năng……………………………………………………..34
4. Cơ sở dữ liệu………………………………………………… 35
5. Usecase……………………………………………………….36
6. Chức năng và giao diện chính……………………………….. 37
4
A.
I.
Tìm hiểu về Flutter
Tổng quan về Flutter
1. Nguồn gốc của Flutter
Flutter là một framework lập trình để xây dựng các ứng dụng di động đa
nền tảng. Nguồn gốc của nó bắt nguồn từ Google Chrome và những nỗ lực
của một nhóm chuyên tinh chỉnh cho web chạy nhanh hơn. Eric Seidel là
người sáng lập dự án Flutter và trong cuộc phỏng vấn trên SE Daily, anh kể
lại cách anh và một vài đồng nghiệp trong nhóm Chrome quyết định xem họ
có thể làm Chrome tải các trang nhanh hơn. Họ đã phát hiện ra rằng phần lớn
code của Chrome đang làm chậm việc load trang web và chỉ có để cung cấp
khả năng tương thích với một bộ phận các trang web rất nhỏ. Họ loại bỏ những
bộ phận đó ra để xem có thể làm nó nhanh như thế nào. Nỗ lực này đã chứng
minh rằng có rất nhiều tiềm năng trong việc tạo ra một framework giao diện
người dùng đa nền tảng thực sự nhanh chóng. Khơng may, nếu Eric và nhóm
của anh ấy muốn nhanh chóng đưa framework UI đa nền tảng vào tay các lập
trình viên thì đó sẽ phải là một thứ gì đó khơng phải là web, vì họ nhận ra
rằng web cập nhật rất chậm khi áp dụng các tiêu chuẩn mới. Do đó, dự án
Flutter đã ra đời.
5
Hình 1: Flutter Studio
Phiên bản đầu tiên của Flutter được gọi là "Sky" và chạy trên hệ điều hành
Android. Nó được công bố tại hội nghị nhà phát triển Dart 2015, với dự định
ban đầu để có thể kết xuất ổn định ở mức 120 khung hình trên giây. Trong bài
phát biểu chính ở hội nghị Google Developer Days tại Thượng Hải, Google
công bố phiên bản Flutter Release Preview 2, đây là phiên bản lớn cuối cùng
trước Flutter 1.0. Vào ngày 4 tháng 12 năm 2018, Flutter 1.0 đã được phát
hành tại sự kiện Flutter Live, là phiên bản "ổn định" đầu tiên của khung ứng
dụng này.
2. Tăng trưởng và Tập trung vào di động
Trong lần đầu tiên ra mắt, Flutter đã bắt đầu từ cơ sở mã Chrome và nhóm
phát triển đã tìm ra thứ gì đó trơng rất giống HTML. Cuối cùng, nhóm bắt đầu
với việc họ chỉ cố gắng tạo ra một ngơn ngữ HTML có thể chạy nhanh.
Nhóm Flutter nhận ra rằng họ sẽ cần phải rời khỏi HTML và suy nghĩ sâu
hơn về cách làm cho việc phát triển giao diện người dùng hiệu quả hơn và dễ
chịu hơn từ góc độ lập trình viên.
Nhóm đã khởi động lại dự án Flutter và đi thẳng vào con đường phát triển
bắt đầu từ JavaScript, xây dựng giải pháp phần tử tùy chỉnh và thao tác với
DOM.
6
Điều đó nghe có vẻ khơng hồn tồn đúng, vì vậy sau đó họ đã cố gắng
render mọi thứ thành phần tử canvas.
Sau đó, nhóm nghiên cứu vì nhiều lý do đã chuyển từ JavaScript sang Dart
và cũng chuyển sang sử dụng mẫu kiểu reactive, thay vì mẫu object-observe.
Một trong những đội đầu tiên tại Google mà nhóm Flutter đã liên hệ là
nhóm Fuchsia. Điều này rất hữu ích trong việc tìm ra ý kiến xung quanh dự
án. Nhóm Flutter có tầm nhìn lớn về việc Flutter cuối cùng có thể là gì, Eric
nhớ lại câu hỏi của nhóm:
Tại sao khơng xây dựng lại việc phát triển có thể dung cho bất kỳ màn hình
nào?
Tuy nhiên, nhóm cho rằng sẽ là khơn ngoan khi tập trung vào các nền tảng
có thể cung cấp giá trị lớn nhất, cho số lượng lớn nhất các lập trình viên trong
thời gian ngắn nhất. Lựa chọn hợp lý là tập trung vào việc cải thiện trải nghiệm
và năng suất của lập trình di động cho iOS và Android.
Ban đầu, họ đã làm việc cho iOS, dành nhiều thời gian để nói chuyện với
khách hàng và nhận ra rằng họ cần dành thời gian tập trung vào Google để
tìm ra khách hàng đầu tiên của Google. Từ việc nói chuyện với các lập trình
viên, họ thấy rằng phần ‘Trải nghiệm dành cho lập trình viên’ đã cung cấp
cho họ rất nhiều giá trị, thậm chí cịn hơn cả các khía cạnh giao diện người
dùng và nền tảng giao diện tùy chỉnh của nó.
3. Kiến trúc Flutter
Vẽ pixel trên màn hình là mục tiêu của tất cả các framework UI. Flutter
khác với các framework nền tảng chéo khác ở chỗ nó hiển thị trực tiếp lên
màn hình thơng qua OpenGL. Các cách tiếp cận khác hoạt động ở mức độ
trừu tượng cao hơn, nói chuyện với các framework UI của các hệ thống cơ
bản tương ứng, từ đó điều khiển render pixel của các thành phần UI.
Ưu điểm của phương pháp này là cần ít giao tiếp qua lại giữa mã cơ bản và
mã Flutter. Có một số sự chậm chạp có thể xảy ra do phải kết nối giữa các
ngôn ngữ, theo quan sát của Eric, và cách tiếp cận của Flutter tránh được phần
lớn sự chậm chạp này.
7
Nhược điểm là bạn khơng cịn có thể dựa vào vật lý hoạt hình đã được tích
hợp trong iOS và Android. Mỗi nền tảng có một cách tiếp cận khác nhau một
cách tinh tế đối với cách UI phản hồi khi cuộn, tải trang, v.v. Và như Eric nhớ
lại, việc viết tương tác vật lý của riêng bạn là khó khăn nhưng cần thiết để
đáp ứng sự mong đợi của người dùng về một điều gì đó về tương tác trong
việc sử dụng từng nền tảng tương ứng.
Flutter chạy tất cả mã của nó trên một luồng riêng biệt từ các khía cạnh cụ
thể của hệ điều hành của ứng dụng. Giao tiếp giữa mã Dart và mã cụ thể của
hệ điều hành thông qua một JSON đơn giản.
Về mặt đồ họa trên màn hình, Flutter sử dụng Skia, đây là thư viện đồ họa
tương tự được sử dụng trên Chrome và Android. Để bố trí văn bản, Flutter
mượn mã đã được phát triển cho Android.
Từ góc độ software stack, Flutter có thể được coi là bao gồm các lớp sau:
+ Lớp thấp nhất là lớp runtime được xây dựng trong C++, cần nói chuyện
với HĐH theo một số cách hạn chế – đến Open GL, API truy cập, tệp và mạng
IO, v.v … Phía trên cùng của lớp này là API chuyển sang mã Dart.
+ Một lớp liên kết chủ yếu là cho thiết lập ban đầu.
+ Một lớp render là một mơ hình view điển hình với các đối tượng tồn tại
lâu. Lớp này xử lý những thứ như bố cục, vẽ, chỉnh sửa văn bản, cử chỉ, v.v.
+ Một lớp widget bao gồm các thứ có thời gian tồn tại ngắn mô tả giao diện
người dùng sẽ trông như thế nào trong một framework duy nhất. Flutter áp
dụng mơ hình lập trình reactive trong đó UI được xây dựng lại mỗi khi trạng
thái thay đổi.
+ Một lớp thể hiện thẩm mỹ thiết kế cụ thể, ví dụ Thiết kế Layout cho
Android.
8
Hình 2: Kiến trúc Flutter
Tại sao lại là Dart?
Một số khía cạnh của Dart khiến nó phù hợp với Flutter là:
+ Nó có một garbage collector thế hệ rất nhanh. Điều này rất hữu ích vì
Flutter tn theo mơ hình lập trình reactive trong đó các đối tượng UI được
tạo và hủy nhanh chóng.
+ Trình biên dịch trước thời hạn của Dart cho phép biên dịch trực tiếp mã.
Điều này cho phép khởi động nhanh và đạt hiệu suất phù hợp.
+ Dart tập trung vào trải nghiệm tốt cho lập trình viên.
+ Dart có thuật tốn tree shaking – chỉ các phần của framework Flutter đã
được sử dụng mới được đưa vào ứng dụng cuối cùng.
9
4. Trải nghiệm của lập trình viên
Cải thiện trải nghiệm của lập trình viên ln là điều tối quan trọng trong việc phát
triển Flutter. Một số cơng cụ và tính năng đã được phát triển cụ thể với ý tưởng này,
ví dụ như hot reload.
Một trong những ý tưởng sáng lập của chúng tôi chỉ là cố gắng làm cho tồn bộ
trải nghiệm của lập trình viên trở nên tốt hơn và Hot Reload là một phần trong đó.
Với hot reload, sau khi viết một số mã trong Dart và lưu nó, mã chạy trong trình
giả lập hoặc điện thoại sẽ được cập nhật ngay lập tức để phản ánh các thay đổi.
Flutter Doctor là một tính năng lấy cảm hứng từ Trải nghiệm lập trình. Nó giúp
chẩn đốn hệ thống của bạn và cài đặt các thành phần phụ thuộc bị thiếu.
Các IDE chính được hỗ trợ là:
+ Android Studio
+ IntelliJ
+ Visual Studio Code
a. Plugin và package
Một nguyên tắc sáng lập của Flutter là bất cứ điều gì mà phần cứng có thể
làm, bạn cũng có thể làm trong Flutter. Mặc dù ln có khả năng đào sâu vào
10
các thư viện cụ thể của nền tảng, với bộ sưu tập các gói Flutter ngày càng phát
triển, hầu hết các lập trình viên sẽ tìm thấy những gì họ cần trên
/>b. Sự quản lý
Về các nguyên tắc hướng dẫn cách vận hành nhóm, Eric cho biết mức độ
gắn kết với người dùng là chìa khóa.
Một số điều đặc trưng cho phương pháp quản lý là:
+ Giúp mọi người thành công.
+ Che chắn mọi người khỏi phiền nhiễu.
+ Đảm bảo các thành viên trong nhóm có được các tài nguyên họ cần.
+ Tập trung vào các tính năng tạo giá trị thực sự.
+ Standups mỗi ngày (5 phút)
c. Lợi ích của Flutter
Không đưa ra bất kỳ so sánh nào với các nền tảng khác, đây là danh sách
một số tính năng có thể khiến bạn cân nhắc việc sử dụng Flutter:
+ Năng suất cao. Vì Flutter là đa nền tảng, bạn có thể sử dụng cùng một
cơ sở mã cho ứng dụng iOS và Android của mình. Điều này chắc chắn có thể
giúp bạn tiết kiệm cả thời gian và nhân lực.
+ Hiệu suất tuyệt vời. Dart biên dịch thành mã native và không cần phải
truy cập các widget OEM vì Flutter đã có sẵn. Điều này có nghĩa là ít giao
tiếp qua trung gian giữa ứng dụng và nền tảng. Như Wm Leler nói, đó là SDK
Flutter là SDK di động duy nhất cung cấp các chế độ xem reactive mà không
yêu cầu cầu nối JavaScript. Tất cả những điều này góp phần vào thời gian
khởi động ứng dụng nhanh và các vấn đề hiệu suất ít hơn.
+ Phát triển nhanh chóng và đơn giản. Một trong những tính năng được
ca ngợi nhất của Flutter là Hot Reloadcho phép bạn xem ngay các thay đổi
được thực hiện trong mã trên trình giả lập và phần cứng. Chưa đầy một giây,
mã đã thay đổi được tải lại trong khi ứng dụng đang chạy mà không cần khởi
động lại. Điều này là tuyệt vời không chỉ để xây dựng UI hoặc thêm các tính
năng mà cịn để sửa lỗi. Về mặt đơn giản, Flutter tuyên bố trong các tài liệu
11
của mình rằng lập trình với Flutter rất dễ đến mức khơng cần phải có kiến
thức lập trình trước: Kinh nghiệm với các ngôn ngữ hướng đối tượng chắc
chắn rất hữu ích, nhưng ngay cả những người khơng lập trình cũng đã tạo ra
các ứng dụng Flutter! Chỉ có một cách để tìm hiểu xem điều này có đúng
khơng.
+ Khả năng tương thích. Vì các widget là một phần của ứng dụng chứ
khơng phải nền tảng, bạn sẽ ít gặp phải hoặc khơng gặp sự cố tương thích trên
các phiên bản HĐH khác nhau. Điều này có nghĩa là ít thời gian dành cho
testing.
+ Nguồn mở. Cả Flutter và Dart đều là nguồn mở và miễn phí, đồng thời
cung cấp tài liệu hỗ trợ và có cộng đồng rộng rãi để giúp giải quyết mọi vấn
đề bạn có thể gặp phải.
5. Điều gì đang làm các lập trình viên ngần ngại
Các lập trình viên xây dựng ứng dụng Android và iOS native có thể bị trì
hỗn do cần phải học một ngơn ngữ lập trình khác là Dart. Và nếu bạn dự định
th một nhóm các lập trình viên Dart cho ứng dụng Flutter của mình, bạn có
thể phải đối mặt với các vấn đề về nhân sự vì khơng có q nhiều người biết
về nó. Tuy nhiên, do tính đơn giản của nó, Dart tương đối dễ nhận và biết một
ngơn ngữ lập trình bổ sung chắc chắn là một lợi thế cho bất kỳ lập trình viên
nghiêm túc nào.
Ngồi ra, Flutter có thể khơng phải là nền tảng bạn chọn khi bạn phát triển
trò chơi hoặc ứng dụng yêu cầu nhiều chức năng dành riêng cho thiết bị.
Tuy nhiên, phần lớn nghi ngờ về Flutter, liên quan đến tính năng mới của
nó. Một số lập trình viên tun bố rằng nó chưa thể được sử dụng để xây dựng
một ứng dụng thương mại phức tạp và nó phù hợp hơn cho các ứng dụng và
tạo mẫu đơn giản hơn. Tuy nhiên, khi tìm kiếm trên Internet, người ta có thể
tìm thấy những câu chuyện thành cơng về các ứng dụng Flutter trong thực tế.
12
6. So sánh Flutter và React Native
Flutter và React Native là hai framework được rất nhiều người quan tâm ở
thời điểm hiện tại. Điểm chung của cả 2 đều là Cross Platform Mobile, build
native cho cả Android và iOS. Cả 2 có thể giao tiếp với native để viết các
module base on native (gần như bắt buộc). Hãy cùng nhìn qua những ưu điểm
và nhược điểm của cả hai công nghệ này nhé.
Flutter
Ưu điểm
- Mạnh về animation, performance app rất cao.
- Giao tiếp gần như trực tiếp với native
- Static language nhưng với syntax hiện đại, compiler linh động giữa
AOT (for archive, build prod) và JIT (for development, hot reload)
- Có thể chạy được giả lập mobile ngay trên web, tiện cho development.
Các metric measure performance được hỗ trợ sẵn giúp developer kiểm
sốt tốt performance của app.
- Có thể dùng để build các bundle/framework gắn và app native để tăng
performance.
Nhược điểm
- Bộ render UI được team author gần như viết lại, khơng liên quan tới UI
có sẵn của Framework native, dẫn đến memory sử dụng khá nhiều.
- Phải học thêm ngơn ngữ DART, bloc pattern, DART Streaming
- Flutter cịn khá mới. Một số plugin rất quan trọng như Google Map vẫn
còn đang phát triển, chưa stable.
- Là con cưng của Google, tuy nhiên hãng dính nhìu phốt với thói quen
“quăng con giữa chợ” nên cần cân nhắc.
React Native
Ưu điểm
- Thiên về development/hotfix nhanh (hot reload, bundle injection)
- Sử dụng JS (quen thuộc với nhiều developer) và có thể share business
logic codebase với frontend (js).
- Back bởi Facebook, họ dùng cho product của họ hàng ngày nên developer
hưởng lợi khá nhiều từ đây.
13
- Hiện tại đã rất nhiều thư viện, gần như đã rất đầy đủ cho các nhu cầu app
thông dụng.
Nhược điểm
- Giao tiếp với native thông qua các bridge, dễ bị bottleneck nếu khơng
được kiểm sốt tốt.
- Dùng JS nên mang theo các đặc điểm của JS: rất dễ làm nhưng cũng dễ
sai, dẫn tới khó maintain về sau.
- HIệu năng animation là điểm yếu của RN, muốn làm tốt phải làm từ
native, tầng js chỉ call vào, setup views. Tuy nhiên với các interactive
animation thì rất đau khổ.
- Khơng thích hợp cho các app cần năng lực tính tốn cao (hash, crypto,
etc).
Tóm lại:
Flutter phù hợp với các dự án focus về animation, các layout phức tạp, với
thế mạnh sử dụng bộ render tự làm, giao tiếp trực tiếp với GPU và một SDK
để viết anim dễ dàng. Cực kỳ phù hợp với các team native (đang có nhu cầu
làm thêm các UX có hiệu năng cao vào app native có sẵn). Flutter Developer
hiện tại chưa nhiều, sẽ khó tìm người hơn.
React Native phù hợp với các team dùng JS as main language, khơng có
q nhiều animation phức tạp. React Native hiện tại tuyển người khá/rất dễ
so với Flutter.
II. Tổng quan về Kiến trúc Flutter
1. Architectural layers
Flutter được thiết kế như một hệ thống nhiều lớp, có thể mở rộng. Nó tồn
tại dưới dạng một loạt các thư viện độc lập mà mỗi thư viện phụ thuộc vào
lớp bên dưới. Khơng có lớp nào có quyền truy cập đặc quyền vào lớp bên
dưới và mọi phần của framework level được thiết kế để trở thành tùy chọn và
có thể thay thế.
14
Đối với hệ điều hành cơ bản, các ứng dụng Flutter được đóng gói giống
như bất kỳ ứng dụng gốc nào khác. Một trình nhúng dành riêng cho nền tảng
cung cấp một điểm nhập; phối hợp với hệ điều hành cơ bản để truy cập vào
các dịch vụ như hiển thị bề mặt, khả năng truy cập và đầu vào; và quản lý
vịng lặp sự kiện tin nhắn. Trình nhúng được viết bằng ngôn ngữ phù hợp với
nền tảng: hiện tại là Java và C ++ cho Android, Objective-C / Objective-C
++ cho iOS và macOS, và C ++ cho Windows và Linux. Sử dụng cơng cụ
nhúng, mã Flutter có thể được tích hợp vào một ứng dụng hiện có dưới dạng
mơ-đun hoặc mã có thể là tồn bộ nội dung của ứng dụng. Flutter bao gồm
một số trình nhúng cho các nền tảng mục tiêu chung, nhưng các trình nhúng
khác cũng tồn tại.
Cốt lõi của Flutter là Flutter engine , phần lớn được viết bằng C ++ và hỗ
trợ các nguyên tắc cần thiết để hỗ trợ tất cả các ứng dụng Flutter. Động cơ
chịu trách nhiệm sắp xếp các cảnh tổng hợp bất cứ khi nào cần sơn một khung
mới. Nó cung cấp khả năng triển khai cấp thấp của API cốt lõi của Flutter,
15
bao gồm đồ họa (thông qua Skia ), bố cục văn bản, tệp và mạng I / O, hỗ trợ
trợ năng, kiến trúc plugin và chuỗi công cụ biên dịch và thời gian chạy Dart.
Công cụ được tiếp xúc với Flutter framework thông qua dart:ui, khung này
bao bọc mã C ++ cơ bản trong các lớp Dart. Thư viện này hiển thị các
primitives cấp thấp nhất, chẳng hạn như các lớp để điều khiển hệ thống con
nhập liệu, đồ họa và văn bản.
Thông thường, các nhà phát triển tương tác với Flutter thông qua Flutter
framework , cung cấp một framework hiện đại được viết bằng ngơn ngữ Dart.
Nó bao gồm một bộ thư viện nền tảng, bố cục và nền tảng phong phú, bao
gồm một loạt các lớp. Từ dưới lên trên, ta có:
+ Các lớp nền tảng cơ bản và các dịch vụ khối xây dựng như hoạt ảnh , vẽ
tranh và cử chỉ cung cấp các nội dung trừu tượng thường được sử dụng trên
nền tảng cơ bản.
+ Lớp kết xuất cung cấp một sự trừu tượng để xử lý bố cục. Với lớp này,
bạn có thể xây dựng một cây các đối tượng có thể kết xuất. Bạn có thể thao
tác động các đối tượng này, với cây tự động cập nhật bố cục để phản ánh các
thay đổi của bạn.
+ Widgets layer là một sự trừu tượng hóa thành phần. Mỗi đối tượng kết
xuất trong lớp kết xuất có một lớp tương ứng trong lớp vật dụng. Ngoài ra,
lớp vật dụng cho phép bạn xác định tổ hợp các lớp mà bạn có thể sử dụng lại.
Đây là lớp mà tại đó mơ hình lập trình phản ứng được giới thiệu.
+ Material và Cupertino: các thư viện cung cấp các bộ điều khiển toàn diện
sử dụng các thành phần nguyên thủy của lớp tiện ích con để triển khai các
ngôn ngữ thiết kế Material hoặc iOS.
Flutter framwork tương đối nhỏ; nhiều tính năng cấp cao hơn mà nhà phát
triển có thể sử dụng được triển khai dưới dạng gói, bao gồm các plugin nền
tảng như camera và webview, cũng như các tính năng bất khả tri nền tảng
như ký tự, http và hoạt ảnh được xây dựng dựa trên thư viện Dart và Flutter
cốt lõi. Một số gói này đến từ hệ sinh thái rộng lớn hơn, bao gồm các dịch vụ
như thanh toán trong ứng dụng, xác thực Apple và hoạt ảnh.
2. Giao diện người dùng phản ứng
Nhìn bề ngồi, Flutter là một khung giao diện người dùng phản ứng, giả
khai báo, trong đó nhà phát triển cung cấp ánh xạ từ trạng thái ứng dụng sang
16
trạng thái giao diện và khung công tác đảm nhận nhiệm vụ cập nhật giao diện
trong thời gian chạy khi trạng thái ứng dụng thay đổi. Mơ hình này được lấy
cảm hứng từ công việc của Facebook cho khung React của riêng họ, bao gồm
việc suy nghĩ lại nhiều nguyên tắc thiết kế truyền thống.
Trong hầu hết các khung giao diện người dùng truyền thống, trạng thái ban
đầu của giao diện người dùng được mô tả một lần và sau đó được cập nhật
riêng biệt bằng mã người dùng trong thời gian chạy, để đáp ứng các sự kiện.
Một thách thức của cách tiếp cận này là, khi ứng dụng ngày càng phức tạp,
nhà phát triển cần phải biết cách trạng thái thay đổi tầng trong toàn bộ giao
diện người dùng. Ví dụ: hãy xem xét giao diện người dùng sau:
Có nhiều nơi có thể thay đổi trạng thái: hộp màu, thanh trượt màu sắc, các
nút radio. Khi người dùng tương tác với giao diện người dùng, các thay đổi
phải được phản ánh ở mọi nơi khác. Tệ hơn nữa, trừ khi được cẩn thận, một
thay đổi nhỏ đối với một phần của giao diện người dùng có thể gây ra hiệu
ứng gợn sóng cho các đoạn mã dường như không liên quan.
Một giải pháp cho điều này là một cách tiếp cận như MVC, trong đó bạn
đẩy các thay đổi dữ liệu vào mơ hình thơng qua bộ điều khiển và sau đó mơ
hình đẩy trạng thái mới đến chế độ xem thông qua bộ điều khiển. Tuy nhiên,
điều này cũng có vấn đề, vì tạo và cập nhật các phần tử giao diện người dùng
là hai bước riêng biệt có thể dễ dàng bị mất đồng bộ.
Flutter, cùng với các framework khác, có một cách tiếp cận thay thế cho
vấn đề này, bằng cách tách giao diện người dùng khỏi trạng thái cơ bản của
17
nó một cách rõ ràng. Với các API kiểu React, bạn chỉ tạo mô tả giao diện
người dùng và khung công tác sẽ xử lý việc sử dụng một cấu hình đó để tạo
và / hoặc cập nhật giao diện người dùng khi thích hợp.
Trong Flutter, các widget (tương tự như các thành phần trong React) được
đại diện bởi các lớp bất biến được sử dụng để cấu hình một cây các đối tượng.
Các widget này được sử dụng để quản lý một cây đối tượng riêng biệt để bố
trí, sau đó được sử dụng để quản lý một cây đối tượng riêng biệt để tổng hợp.
Về cốt lõi của nó, Flutter là một loạt các cơ chế để đi bộ một cách hiệu quả
các phần đã sửa đổi của cây, chuyển đổi cây của các đối tượng thành các cây
cấp thấp hơn của các đối tượng và truyền bá những thay đổi trên các cây này.
Một widget khai báo giao diện người dùng của nó bằng cách ghi đè phương
thức build (), là một hàm chuyển đổi trạng thái thành UI:
UI = f(state)
Phương thức build () được thiết kế nhanh chóng để thực thi và khơng có tác
dụng phụ, cho phép nó được gọi bởi khung cơng tác bất cứ khi nào cần (có
khả năng thường xuyên như một lần cho mỗi khung được kết xuất).
Cách tiếp cận này dựa trên một số đặc điểm nhất định của thời gian chạy
ngôn ngữ (đặc biệt là việc khởi tạo và xóa đối tượng nhanh). May mắn thay,
Dart đặc biệt thích hợp cho nhiệm vụ này.
3. Widget
a. Thành phần
Các widget thường bao gồm nhiều widget nhỏ, có mục đích duy nhất khác,
kết hợp với nhau để tạo ra các hiệu ứng mạnh mẽ.
Nếu có thể, số lượng các khái niệm thiết kế được giữ ở mức tối thiểu trong
khi vẫn cho phép tổng lượng từ vựng lớn. Ví dụ, trong lớp widget, Flutter sử
dụng cùng một khái niệm cốt lõi (Widget) để thể hiện bản vẽ lên màn hình,
bố cục (định vị và định cỡ), tương tác của người dùng, quản lý trạng thái, chủ
đề, hoạt ảnh và điều hướng. Trong lớp hoạt ảnh, một cặp khái niệm, Hoạt ảnh
và Tweens, bao phủ hầu hết không gian thiết kế. Trong lớp kết xuất,
RenderObjects được sử dụng để mô tả bố cục, sơn, thử nghiệm lần truy cập
18
và khả năng tiếp cận. Trong mỗi trường hợp này, lượng từ vựng tương ứng sẽ
rất lớn: có hàng trăm widget và các đối tượng kết xuất, và hàng chục loại hoạt
hình và tween.
Hệ thống phân cấp lớp có chủ ý nơng và rộng để tối đa hóa số lượng kết hợp
có thể, tập trung vào các vật dụng nhỏ, có thể kết hợp mà mỗi vật dụng làm
tốt một việc. Các tính năng cốt lõi là trừu tượng, thậm chí các tính năng cơ
bản như đệm và căn chỉnh được triển khai dưới dạng các thành phần riêng
biệt thay vì được tích hợp vào lõi. (Điều này cũng trái ngược với các API
truyền thống hơn, nơi các tính năng như đệm được tích hợp vào cốt lõi chung
của mọi thành phần bố cục.) Vì vậy, ví dụ: để căn giữa tiện ích con, thay vì
điều chỉnh thuộc tính Căn chỉnh danh nghĩa, bạn bọc nó trong tiện ích con
Trung tâm .
Có các widget để đệm, căn chỉnh, hàng, cột và lưới. Các widget bố cục này
khơng có phần trình bày trực quan của riêng chúng. Thay vào đó, mục đích
duy nhất của họ là kiểm sốt một số khía cạnh của bố cục tiện ích con khác.
Flutter cũng bao gồm các widget tiện ích tận dụng cách tiếp cận tổng hợp này.
Ví dụ: Container, một widget thường được sử dụng, được tạo thành từ một
số widget chịu trách nhiệm về bố cục, sơn, định vị và định cỡ. Cụ thể,
Container được tạo thành từ các widget LimitedBox, ConstrainedBox, Align,
Padding, DecoratedBox và Transform, như bạn có thể thấy bằng cách đọc mã
nguồn của nó. Một đặc điểm xác định của Flutter là bạn có thể đi sâu vào
nguồn của bất kỳ widget nào và kiểm tra nó. Vì vậy, thay vì phân lớp vùng
chứa để tạo ra hiệu ứng tùy chỉnh, bạn có thể soạn nó và các widget đơn giản
khác theo những cách mới lạ hoặc chỉ cần tạo một widget mới bằng cách sử
dụng Container làm nguồn cảm hứng.
b. Xây dựng Widget
Như đã đề cập trước đó, bạn xác định cách trình bày trực quan của một
widget bằng cách ghi đè hàm build () để trả về một cây phần tử mới. Cây này
đại diện cho một phần của tiện ích con trong giao diện người dùng theo các
thuật ngữ cụ thể hơn. Ví dụ: tiện ích con trên thanh cơng cụ có thể có chức
năng xây dựng trả về bố cục ngang của một số văn bản và các nút khác nhau.
Khi cần thiết, framework yêu cầu mỗi widget xây dựng một cách đệ quy cho
đến khi cây được mơ tả hồn tồn bằng các đối tượng có thể kết xuất cụ thể.
19
Sau đó, khung cơng tác sẽ ghép các đối tượng có thể kết xuất lại với nhau
thành một cây đối tượng có thể kết xuất.
Chức năng xây dựng của tiện ích khơng được có tác dụng phụ. Bất cứ khi
nào hàm được yêu cầu xây dựng, widget sẽ trả về một cây widget1 mới, bất
kể widget trả về trước đó là gì. Khung làm việc nặng nhọc để xác định phương
thức xây dựng nào cần được gọi dựa trên cây đối tượng kết xuất (được mô tả
chi tiết hơn ở phần sau). Thơng tin thêm về q trình này có thể được tìm thấy
trong chủ đề Inside Flutter.
Trên mỗi khung được hiển thị, Flutter chỉ có thể tạo lại các phần của giao
diện người dùng mà trạng thái đã thay đổi bằng cách gọi phương thức build
() của tiện ích con đó. Do đó, điều quan trọng là các phương thức xây dựng
phải trả về nhanh chóng và cơng việc tính tốn nặng nề nên được thực hiện
theo một số cách khơng đồng bộ và sau đó được lưu trữ như một phần của
trạng thái để một phương thức xây dựng sử dụng.
Mặc dù cách tiếp cận tương đối đơn giản, nhưng so sánh tự động này khá
hiệu quả, cho phép các ứng dụng tương tác, hiệu suất cao. Và, thiết kế của
chức năng xây dựng đơn giản hóa mã của bạn bằng cách tập trung vào việc
khai báo tiện ích con được làm bằng gì, thay vì sự phức tạp của việc cập nhật
giao diện người dùng từ trạng thái này sang trạng thái khác.
c. Widget state
Framwork giới thiệu hai lớp chính của widget: Stateful Widget và Stateless
Widget.
Nhiều tiện ích khơng có trạng thái có thể thay đổi: chúng khơng có bất kỳ
thuộc tính nào thay đổi theo thời gian (ví dụ: biểu tượng hoặc nhãn). Các
widget này phân lớp StatelessWidget.
Tuy nhiên, nếu các đặc điểm riêng biệt của tiện ích con cần thay đổi dựa
trên tương tác của người dùng hoặc các yếu tố khác, thì tiện ích đó là trạng
thái. Ví dụ: nếu một tiện ích con có bộ đếm tăng lên bất cứ khi nào người
dùng nhấn vào một nút, thì giá trị của bộ đếm là trạng thái cho tiện ích con
đó. Khi giá trị đó thay đổi, tiện ích con cần được xây dựng lại để cập nhật
phần giao diện người dùng của nó. Các widget này phân lớp StatefulWidget,
và (vì bản thân widget là bất biến) chúng lưu trữ trạng thái có thể thay đổi
trong một lớp riêng biệt phân lớp State. StatefulWidgets khơng có phương
20
pháp xây dựng; thay vào đó, giao diện người dùng của họ được xây dựng
thông qua đối tượng State của họ.
Bất cứ khi nào bạn thay đổi đối tượng State (ví dụ: bằng cách tăng bộ đếm),
bạn phải gọi setState () để báo hiệu khung cập nhật giao diện người dùng bằng
cách gọi lại phương thức xây dựng của State.
Việc có các đối tượng widget và trạng thái riêng biệt cho phép các widget
khác xử lý cả các Stateful widget và Stateless widget theo cùng một cách mà
không lo bị mất trạng thái. Framework thực hiện tất cả công việc tìm và sử
dụng lại các đối tượng trạng thái hiện có khi thích hợp.
d. Quản lý State
Như với bất kỳ lớp nào khác, bạn có thể sử dụng một hàm tạo trong tiện ích
con để khởi tạo dữ liệu của nó, vì vậy một build()phương thức có thể đảm bảo
rằng bất kỳ tiện ích con nào đều được khởi tạo với dữ liệu mà nó cần:
@override
Widget build(BuildContext context) {
return ContentWidget(importantState);
}
Tuy nhiên, khi cây widget ngày càng sâu, việc chuyển thông tin trạng thái
lên và xuống hệ thống phân cấp cây trở nên cồng kềnh. Vì vậy, loại widget
thứ ba InheritedWidget, cung cấp một cách dễ dàng để lấy dữ liệu từ tổ tiên
được chia sẻ. Bạn có thể sử dụng InheritedWidget để tạo một widget trạng
thái bao bọc một tổ tiên chung trong cây widget, như được minh họa trong ví
dụ sau:
21
Bất cứ khi nào một trong các đối tượng ExamWidgethoặc GradeWidgetđối
tượng cần dữ liệu StudentState, giờ đây nó có thể truy cập nó bằng một lệnh
như:
final studentState = StudentState.of(context);
of(context)gọi nhận bối cảnh xây dựng (một xử lý đến vị trí tiện ích con hiện
tại) và trả về tổ tiên gần nhất trong cây phù hợp với StudentState.
InheritedWidgets cũng cung cấp một updateShouldNotify() - phương thức mà
Flutter gọi để xác định xem một thay đổi trạng thái có nên kích hoạt việc xây
dựng lại các tiện ích con sử dụng nó hay không.
Bản thân Flutter sử dụng InheritedWidgetrộng rãi như một phần của
framework cho trạng thái chia sẻ, chẳng hạn như chủ đề trực quan của ứng
dụng , bao gồm các thuộc tính như kiểu màu và kiểu phổ biến trong ứng dụng.
Các MaterialApp build()phương pháp chèn một chủ đề trong cây khi nó được
xây dựng, và sau đó sâu hơn trong hệ thống phân cấp một widget có thể sử
dụng các .of()phương pháp để tìm kiếm các dữ liệu chủ đề có liên quan, ví
dụ:
Container(
color: Theme.of(context).secondaryHeaderColor,
child: Text(
22
'Text with a background color',
style: Theme.of(context).textTheme.headline6,
),
);
Cách tiếp cận này cũng được sử dụng cho Navigator , cung cấp định tuyến
trang; và MediaQuery , cung cấp quyền truy cập vào các chỉ số màn hình như
hướng, kích thước và độ sáng.
Khi các ứng dụng ngày càng phát triển, các cách tiếp cận quản lý nhà nước
tiên tiến hơn giúp giảm thiểu việc tạo và sử dụng các tiện ích trạng thái trở
nên hấp dẫn hơn. Nhiều ứng dụng Flutter sử dụng các gói tiện ích như nhà
cung cấp , cung cấp một trình bao bọc xung quanh InheritedWidget. Kiến trúc
phân lớp của Flutter cũng cho phép các phương pháp tiếp cận thay thế để thực
hiện việc chuyển đổi trạng thái thành giao diện người dùng, chẳng hạn như
gói Flutter_hooks .
4. Kết xuất và bố cục
a. Mơ hình kết xuất của Flutter
Thật hữu ích khi bắt đầu bằng cách nghĩ về cách các ứng dụng Android
truyền thống hoạt động. Khi vẽ, trước tiên bạn gọi mã Java của khuôn khổ
Android. Thư viện hệ thống Android cung cấp các thành phần chịu trách
nhiệm vẽ chính chúng vào một đối tượng Canvas, sau đó Android có thể kết
xuất với Skia , một cơng cụ đồ họa được viết bằng C / C ++ gọi CPU hoặc
GPU để hoàn thành bản vẽ trên thiết bị.
Các khuôn khổ đa nền tảng thường hoạt động bằng cách tạo ra một lớp trừu
tượng trên các thư viện giao diện người dùng Android và iOS gốc bên dưới,
cố gắng giải quyết các mâu thuẫn của mỗi biểu diễn nền tảng. Mã ứng dụng
thường được viết bằng ngôn ngữ thông dịch như JavaScript, ngôn ngữ này
phải tương tác với các thư viện hệ thống iOS dựa trên Java hoặc Objective-C
dựa trên iOS để hiển thị giao diện người dùng. Tất cả điều này làm tăng thêm
chi phí có thể quan trọng, đặc biệt là khi có nhiều tương tác giữa giao diện
người dùng và logic ứng dụng.
Ngược lại, Flutter giảm thiểu những điều trừu tượng đó, bỏ qua các thư
viện tiện ích con giao diện người dùng hệ thống để có lợi cho bộ tiện ích con
của chính nó. Mã Dart vẽ hình ảnh của Flutter được biên dịch thành mã gốc,
23
sử dụng Skia để hiển thị. Flutter cũng nhúng bản sao Skia của riêng mình như
một phần của cơng cụ, cho phép nhà phát triển nâng cấp ứng dụng của họ để
luôn cập nhật các cải tiến hiệu suất mới nhất ngay cả khi điện thoại chưa được
cập nhật phiên bản Android mới. Điều này cũng đúng với Flutter trên các nền
tảng gốc khác, chẳng hạn như iOS, Windows hoặc macOS.
b. Từ đầu vào của người dùng đến GPU
Nguyên tắc ghi đè mà Flutter áp dụng cho đường dẫn kết xuất của nó là đơn
giản là nhanh chóng . Flutter có một đường dẫn đơn giản về cách dữ liệu
truyền đến hệ thống, như thể hiện trong sơ đồ trình tự sau:
c. Xây dựng: từ Widget thành Element
Trong giai đoạn xây dựng, Flutter dịch các widget được thể hiện bằng mã
thành một cây phần tử tương ứng , với một phần tử cho mỗi widget. Mỗi phần
tử đại diện cho một phiên bản cụ thể của tiện ích con ở một vị trí nhất định
của cấu trúc phân cấp cây. Có hai loại phần tử cơ bản:
ComponentElement, một máy chủ cho các yếu tố khác.
RenderObjectElement, một yếu tố tham gia vào các giai đoạn bố trí .
24