CHƯƠNG 1: CƠ SỞ LÝ THUYẾT 1. TÌM HIỂU VỀ FLUTTER 1. Flutter làgì? Flutter làmobile UI framework của Google để tạo ra các giao diện chất lượng cao trên iOS vàAndroid trong khoảng thời gian ngắn. Flutter hoạt động với những code sẵn có được sử dụng bởi các lập trì nh viên, các tổ chức.
Flutter được phát triển nhằm giải quyết bài toán thường gặp trong mobile làFast Development và Native Performance. Nếu như React Native chỉ đảm bảo Fast Development vàcode native thuần chỉ đảm bảo Native Performance thìFlutter làm được cả 2 điều trên. Flutter Framework Model Cấu thành như thế nào? Flutter được viết chia làm hai tầng. Tầng ở trên sử dụng ngôn ngữ Dart cung cấp các đoạn mã xây dựng lên một ứng dụng Flutter.
Các đoạn mã này cung cấp phương tiện để có thể thay đổi và chỉnh sửa chúng. Từ đó giúp ứng dụng của lập trình viên có thể được tùy chỉnh theo mong muốn. Tầng Application này giúp lập trình viên thay đổi mã nguồn ứng dụng ở thời điểm compile time. Tầng thứ hai của Flutter nằm ở sâu bên dưới và được viết bằng C++.
Tầng Shell này chứa các công tụ trợ giúp ứng dụng Flutter trong quá trình chạy. Nổi bật cần lưu ý ở tầng này là máy ảo Dart VM. Khái niệm máy ảo là khái niệm về một ứng dụng chạy song song với mã nguồn chính như một phần của ứng dụng. Máy ảo Dart VM có ba nhiệm vụ chính bao gồm.
Làm ứng dụng trung gian giữa mã nguồn được viết bởi Dart và thiết bị phần cứng (hoặc phần mềm nằm ngoài ứng dụng). Thông dịch các đoạn mã Dart theo phương thức JIT (Just in time - mã nguồn chỉ được thông dịch khi được gọi đến) hoặc AOT (Ahead of Time – Mã) 12 do an Thực thi các đoạn mã đã được thông dịch hoặc biên dịch cũng như cung cấp các runtime system bao gồm garbage collector, một vài các thư viện cần có của ngôn ngữ. So Sánh với các Cross-platform framework khác. Một ứng dụng để chạy được trên các thiết bị thông thường sẽ tạm quan tâm tới hai thành phần.
Thành phần gần với lập trình viên hơn là lớp Application. Lớp Application chứa các đoạn mã được viết bởi lập trình viên và các công cụ giúp ứng dụng hoạt động và quản lý hoạt động của ứng dụng. Thành phần được quan tâm thứ hai là lớp Platform ở đây dùng để chỉ các hệ điều hành hoặc các ứng dụng trung gian giữa ứng dụng của lập trình viên và thiết bị. Trong phạm vi lập trình ứng dụng mobile, Lớp Platform được chia làm ba thành phần bao gồm.
Services: Bao gồm các ứng dụng được viết và cài đặt mặc định trong thiết bị có trách nhiệm quản lý giao tiếp giữa các ứng dụng trong thiết bị với nhau, cung cấp thông tin của thiết bị cho các ứng dụng hoặc thực thi các yêu cầu của ứng dụng để điều khiển thiết bị (Location, Camera, Sensors. Canvas/Events: Là các ứng dụng giúp hiển thị giao diện lên màn hình hoặc các thiết bị trình chiếu đồng thời nhận lại các sự kiện xuất hiện trên các giao diện này (ví dụ như tương tác của người dùng hoặc các sự kiện từ các animation. OEM Widgets: Thành phần phụ được cấu thành do sự thống nhất giữa các vendor (nhà cung cấp thiết bị (HTC), đơn vị phát hành thiết bị (NTT Docomo)) nhằm thống nhất một quy chuẩn chung cho các UI (thành phần giao diện) được sử dụng trong các Platform. Quy chuẩn được thống nhất này tạo ra một vài giới hạn cho việc viết lên UI sẽ được nói kĩ ở phần sau.
Thành phần sẽ được so sánh trong phạm vi bài viết này là kiến trúc của lớp Application cũng như cách mà lớp Application giao tiếp với lớp Platform. Giống như đã đề cập ở phần trước. Tầng Application của Flutter cung cấp kiến trúc cho một ứng 13 do an dụng viết bằng Flutter và tầng Shell cung cấp khả năng giao tiếp giữa ứng dụng viết bằng Flutter và lớp Platform. Lấy ví dụ về một ứng dụng được viết bằng đoạn mã Native.
Toàn bộ mã thực thi được viết ở dạng Native sẽ được biên dịch hoặc thông dịch qua dạng mà tầng Platform có thể hiểu được và thực thi trên đó. Đối với ứng dụng viết ở dạng Hybrid, các đoạn mã giao diện của ứng dụng được viết bằng HTML/CSS và được vẽ ra với DOM qua dạng hiển thị được trên WebView. WebView sẽ trực tiếp điều khiển Canvas vẽ lên UI và nhận các event ngược lại thông qua WebView đó. Mã thực thi của các ứng dụng viết dựa trên Hybrid được sử dụng dưới dạng Javascript.
JavaScript có thể dễ dàng điều khiển HTML/CSS thông qua giao tiếp với WebView tuy nhiên nhằm mục đích bảo mật, WebView không được cung cấp khả năng giao tiếp với các services hoặc điều khiển phần cứng của lớp Platform dẫn đến các ứng dụng viết dựa trên Hybrid cần một module trung gian thường gọi là Bridge để làm điều này. Module này phải đọc hiểu Javascript và tồn tại luôn trong mãnguồn của ứng dụng dẫn đến kích thước của ứng dụng bị tăng lên đáng kể3. Đối với các ứng dụng được viết ở dạng WebNative hoặc Cross compiled, sẽ không có phần WebView được sử dụng mà thay vào đó module Bridge sẽ thực hiện toàn bộ các hành vi trung gian giữa lớp Application và lớp Shell. Mã nguồn của ứng dụng cũng không bị giới hạn bởi Javascript nữa mà tùy thuộc vào nhà phát triển các nền tảng dạng này.
Có thể là Native Code có thể là Non-native code. Đối với Flutter, mã nguồn được cross compile thành native code. Dựa vào máy ảo Dart VM, những thành phần ít thay đổi sẽ được compile dạng AOT còn những thành phần thường xuyên thay đổi sẽ được compile thành dạng JIT. Flutter không cam kết với các OEM Widgets.
Flutter cho phép lập trình viên thay đổi và điều khiển từng pixel trên màn hình và không cần quan tâm đến những giới hạn của OEM Widgets. Tuy nhiên khác với các ứng dụng viết ở dạng Hybrid khi lập trình viên phải tự quan tâm đến các chuẩn của OEM Widgets, Flutter cũng cung cấp các Widget mặc định hỗ trợ hai nền tảng giao diện là Material Design (cho Android/Fuchsia) và 14 do an Cupertino (cho iOS). Bạn cũng có thể quay trờ về với Flat Design thông qua một số thư viện trôi nổi trên thị trường. Các Widget trong flutter Trong Flutter, mọi thứ đều làWidgets vậy Widget làgì ? Chúng ta xét qua thử một đoạn code mẫu bên dưới.
15 do an Đây là hai class quan trọng nhất trong Flutter. Theo đó, class Widget chịu trách nhiệm hình thành cấu trúc của Diagnosticable Tree4 (Cây chuẩn đoán là một cấu trúc dữ liệu dạng cây hỗ trợ việc định nghĩa cấu trúc giao diện được vẽ lên trong ứng dụng viết bằng Flutter) trong khi class Element chịu trách nhiệm quản lý trạng thái của từng Widget trên cái cây đó. Tư tưởng cơ bản của Flutter tương tự như một Web Application. Tất cả trong một.
Flutter căng ra một mảnh vải làcanvas vàvẽ tất cả mọi thứ lên đó. Khi trạng thái của dữ liệu thay đổi vídụ như người dùng chuyển màn hì nh hay thay đổi dữ liệu trên màn hình được phản ánh thông qua việc xóa đi các Widget cũ nh vìvậy thay vìphải biết đến các StoryBoard (trong vàvẽ lên các Widget mới. Chí iOS) hay các Activity (trong Android), Flutter đưa tất cả các khái niệm liên quan đến giao diện về một khái niệm duy nhất gọi làWidget. Việc quản lý trạng thái của các Widget cũng được đưa về cho lập trình viên thực hiện.
Điểm khác biệt này cũng đặc biệt hơn khi Dart là ngôn ngữ Component Based. Trong Flutter, khi muốn điều chỉnh trạng thái về kích thước hay vị trícủa một Widget nào đó, ta không thực hiện việc đó trong Widget hiện tại mà được khuyến khí ch bọc Widget đó trong một Widget nào đó chỉ chuyên làm việc này. Điều này khiến cho tí nh chất "Trong Flutter thìmọi thứ đều làWidget" lại càng chuẩn hơn bao giờ hết. Màn hì nh làWidget, thành phần giao diện cũng là Widget, thậm chícả thông tin về layout cũng làWidget.
Một điểm nữa cần lưu tâm cũng là đặc tí nh của Widget trong Flutter đó là thuộc nh Widget#key. Mọi Widget đều độc lập. Lído làvìWidget không thể tự vẽ lại bản tí thân. Để thực hiện điều này ta cần thông báo cho Element.
Cách dễ nhất để cóthể dễ dàng thông báo cho Element làlàm bẩn (dirty) instance tương ứng dẫn đến Widget Tree được vẽ lại. Widget Tree được vẽ lại thìinstance của Widget cũ sẽ không còn. 16 do an Trong một vài trường hợp cần phải tìm lại giátrị của Widget tại vị trí được vẽ lại, ta sử dụng key làm chìa khóa cho vấn đề này. StatefulWidget làgì? Đi qua một vídụ về StatefulWidget để dễ hì nh dung.
Khi tạo mới một StatefulWidget, ta quan tâm đến hai class làStatefulWidget vàState của Widget đó. StatefulWidget là phần không thay đổi trong Widget Tree, thay vào đó, State làphần được thay đổi. Mỗi khi Widget bị làm bẩn, state của Widget đó sẽ được khởi tạo lại thông qua việc gọi đến phương thức StatefulWidget#createState(). Generic type5 (kiểu giữ chỗ) của State định nghĩa ra kiểu dữ liệu của thuộc tí nh State#widget chứa trong nó.
Thuộc tính này chí nh là 17 do an instance của StatefulWidget đã tạo ra State đó. Chính nhờ vậy, từ trong State hoàn toàn cóthể lấy được những giátrị được truyền vào bên trong StatefulWidget thay vì phải truyền vào thông qua hàm khởi tạo. ExampleStatefulWidget class nằm trong Widget Tree và ít thay đổi. Thay vìtạo một class dễ thay đổi trong cây, Flutter cung cấp cho Widget này một thành phần gọi làState.
Trong State chứa một thể hiện của Element tương ứng trong cây thông qua State#_element. Khi cần vẽ lại, có hai sự kiện được sử dụng để làm bẩn Element làdidUpdateWidget() vàsetState(). Ở hàm thứ nhất, khi configuration bị thay đổi, Widget sẽ được thông báo về sự thay đổi này. Lập trình viên @override lại phương thức didUpdateWidget() để bắt sự kiện trước khi Flutter build lại.
Còn để thực hiện yêu cầu Widget thay đổi State, lập trì nh viên sử dụng phương thức setState(). Trong phương thức setState()cócho phép truyền vào một hàm. Mục đích của việc này là đôi khi công việc build lại Widget sẽ tốn một khoảng thời gian trước khi mọi thứ hoàn thành. Hàm callback được truyền vào sẽ đảm bảo Flutter thực thi được trọn vẹn công việc của mì nh.
Vídụ sau khi thay đổi kích thước của một list view màmuốn scroll xuống cuối list. Statelesswidget làgì? Bên cạnh khái niệm về StatefulWidget ta cũng có StatelessWidget. Cách thức để khai báo thì đơn giản hơn rất nhiều và cũng vô cùng nhạt nhẽo. Đại để là cái gì mà đưa nó thành StatelessWidget được thì nên để nólàStatelessWidget.
Phương thức render của flutter Flutter sử dụng Diff Algorithm để xác định sự thay đổi trong Widget Tree.