Category: Uncategorized

  • JSON vs YAML: A Dive Into 2 Popular Data Serialization Languages

    Bất kỳ người nào quan tâm đến lập trình và công nghệ đều biết JSON là gì. YAML không phổ biến như JSON, nhưng nó cũng là một ngôn ngữ tuần tự hóa dữ liệu phổ biến và tuyệt vời. Ví dụ, bất kỳ người nào đã sử dụng Docker chắc chắn biết YAML là gì.

    Trước hết, hãy xem tuần tự hóa dữ liệu nghĩa là gì. Theo Devopedia, tuần tự hóa dữ liệu là quá trình chuyển đổi các đối tượng dữ liệu có trong cấu trúc dữ liệu phức tạp thành một luồng byte cho các mục đích lưu trữ, truyền và phân phối trên các thiết bị vật lý. Vì vậy, JSON và YAML đều là một cách lưu trữ các đối tượng và cấu trúc dữ liệu trong tệp.

    JSON là gì?

    Mặc dù hầu hết chúng ta đều biết JSON là gì, nhưng chúng ta hãy giới thiệu nhanh. JSON là tên viết tắt của JavaScript Object Notation. JSON dựa trên một tập con của tiêu chuẩn ngôn ngữ lập trình JavaScript ECMA-262 3rd Edition-December 1999. JSON được sử dụng rộng rãi với JavaScript nhưng vì nó không phụ thuộc vào ngôn ngữ nên nó có thể được sử dụng với bất kỳ ngôn ngữ lập trình nào.

    JSON có một định dạng tiêu chuẩn để lưu trữ dữ liệu. Nó lưu trữ dữ liệu trong các cặp khóa / giá trị. Các bản ghi được phân tách bằng dấu phẩy và cả tên trường và chuỗi đều được đặt trong dấu ngoặc kép.

    YAML là gì?

    YAML là tên viết tắt của YAML Ain’t Markup Language. Và YAML Ain’t Markup Language là tên viết tắt của YAML Ain’t Markup Language Ain’t Markup Language. Khá tuyệt, phải không? Để làm cho mọi thứ thú vị hơn, trang web chính thức của YAML cũng được hiển thị ở định dạng YAML.

    YAML sử dụng ba dấu gạch ngang (—) để biểu thị phần bắt đầu của tài liệu và ba dấu chấm (…) để biểu thị phần cuối của tài liệu. Không giống như JSON, YAML sử dụng thụt lề giống như trong Python để hiển thị các cấp trong dữ liệu. Các cặp khóa / giá trị được phân tách bằng dấu hai chấm và danh sách bắt đầu bằng dấu gạch ngang trong YAML. Và các tệp YAML cũng được viết với phần mở rộng YML ở một số nơi và cả .YAML và .YML đều có nghĩa là cùng một loại tệp.

    Pros and Cons: JSON vs. YAML

    Về mặt lý thuyết, cả JSON và YAML đều sẽ thực hiện cùng một nhiệm vụ, tức là cung cấp định dạng trao đổi dữ liệu có thể đọc được của người dùng.

    Khả năng đọc và tính linh hoạt

    Mục tiêu thiết kế của JSON là càng đơn giản càng tốt và có thể sử dụng được trên toàn cầu. Điều này đã làm giảm khả năng đọc của dữ liệu ở một mức độ nào đó. Ngược lại, mục tiêu thiết kế của YAML là cung cấp một định dạng tốt mà con người có thể đọc được và cung cấp hỗ trợ cho việc tuần tự hóa các cấu trúc dữ liệu gốc tùy ý. Điều này đã làm tăng khả năng đọc của các tệp YAML, nhưng nó đã làm cho việc phân tích cú pháp và tạo tệp hơi phức tạp. Chúng ta có thể thấy rõ điều này trong trang web chính thức của YAML, nơi nó hiển thị nội dung ở định dạng YAML: Bất kỳ ai truy cập trang web cũng có thể dễ dàng đọc được. Mặt khác, nếu nó được hiển thị ở định dạng JSON, trang web sẽ vô dụng.

    Người ta nói rằng YAML là một tập siêu định dạng JSON. Điều này có nghĩa đơn giản là chúng ta có thể phân tích cú pháp JSON bằng trình phân tích cú pháp YAML. Tuy nhiên, trong các tình huống thực tế, việc phân tích cú pháp này có thể gây ra vấn đề, nhưng về mặt lý thuyết thì hoàn toàn có thể.

    Hiệu suất tuần hoàn

    Trong cuộc thi tuần tự hóa dữ liệu, JSON là người chiến thắng vì khả năng phân tích cú pháp dữ liệu được tuần tự hóa JSON một cách nhanh chóng và dễ dàng với thiết kế đơn giản hơn. Và điều này đã làm cho JSON phổ biến hơn trong số các nhà phát triển, dẫn đến ngày càng có nhiều hỗ trợ gốc hơn và điều này đã cải thiện hiệu suất một lần nữa. Do đó JSON đã trở thành định dạng trao đổi dữ liệu được sử dụng rộng rãi nhất cho các ứng dụng web và dịch vụ web.

    Sự hỗ trợ

    Đối với bất kỳ ngôn ngữ lập trình nào, chúng ta có thể dễ dàng tìm thấy một thư viện JSON được tích hợp với ngôn ngữ này do tính phổ biến, dễ thực hiện và đơn giản của nó. Trang web chính thức của JSON liệt kê nhiều ngôn ngữ với nhiều thư viện hỗ trợ cho JSON. YAML cũng được hỗ trợ rộng rãi và nhiều thư viện để tích hợp nó với nhiều ngôn ngữ khác nhau, nhưng không nhiều như JSON. Bạn có thể lấy danh sách các thư viện và ngôn ngữ hỗ trợ YAML tại đây.

    Khả năng bình luận

    Cho đến nay, chúng ta đã thảo luận về những ưu điểm của JSON so với YAML. Nhưng một số tính năng quan trọng đáng kể của YAML không được tìm thấy với JSON. YAML hỗ trợ nhận xét mà JSON không hỗ trợ. Chúng ta có thể nhận xét ở bất kỳ đâu trong tài liệu bằng ký tự # đơn giản. Điều này đã được chứng minh là có lợi khi viết các tệp cấu hình nơi một nhà phát triển có thể dễ dàng mô tả cấu hình bằng cách sử dụng các nhận xét. Do đó, định dạng YAML được sử dụng trong nhiều ngăn xếp công nghệ như ElasticSearch và Docker để lưu trữ thông tin cấu hình.

    Khả năng sử dụng các cấu trúc phúc tạp

    Một tính năng khác mà YAML cung cấp là khả năng tham chiếu đến các đối tượng dữ liệu khác. Với tham chiếu này, có thể ghi dữ liệu đệ quy trong tệp YAML.

    Đối với điều này, chúng tôi có thể xác định neo trong tệp YAML bằng cách sử dụng & và tham chiếu đến chúng sau này bằng bí danh, *. Đây là một tính năng rất quan trọng trong YAML mà JSON không cung cấp. Trong JSON, không thể tuần tự hóa các cấu trúc phức tạp với các tham chiếu đối tượng. Nhưng tính năng trên trong YAML giải quyết được vấn đề đó. Nhưng một nhược điểm của điều này là khả năng lặp lại vô hạn trong một số bộ chuyển đổi.

    Vì vậy, từ tất cả những điểm này, chúng ta có thể thấy rằng cả JSON và YAML đều có điểm mạnh và điểm yếu của họ. Một nhà phát triển giỏi phải có thể xác định những điều này và sử dụng đúng định dạng ở đúng vị trí.

    Ví dụ:

    Yaml file:

    Json file:

    Tổng kết:

    Trên đây là 1 số chia sẻ về JSON vs YAML mong có thể giúp đỡ mọi người.

    Author: DuongVT19

  • SỬ DỤNG RETROFIT TRONG FLUTTER

    Trong bài viết này tôi sẽ giới thiệu về retrofit trong Flutter và cách sử dụng retrofit Flutter.

    Retrofit là gì ?

    Trong Android, Retrofit là một HTTP client type-safe cho Android & Java, giúp dễ dàng kết nối đến một dịch vụ REST API trên web bằng cách chuyển đổi API thành Java Interface.

    Theo khái niệm chung thì Retrofit là một thư viện dùng để gọi Rest API bằng cách gửi các dynamic header, parameter, print request và response theo cách bảo mật ( secured way).

    Cách sử dụng Retrofit trong Flutter

    Hãy tạo một project mới để sử dụng retrofit Flutter !

    + Tích hợp thư viện
    Trong file : pubspec.yaml, thêm các thư viện package : retrofit, dio, logger, retrofit_generator, build_runner, json_annotation, json_serializable ; khai báo các thư viện như hình dưới :

    + Tạo các file

    + Tạo package : services, trong package tạo file : post_api_service.dart có nội dụng như bên dưới :

    bạn thấy báo rất nhiều lỗi ?
    Đừng quá lo lắng, chạy dòng lệnh trong mục terminal : flutter pub run build_runner build
    Trong quá trình chạy bạn thấy báo lỗi : Missing “part ‘post_api_service.g.dart’;”. ?

    Thêm khai báo : part ‘post_api_service.g.dart và tiếp tục chạy tiếp dòng lệnh trên : flutter pub run build_runner build
    Khi đó file post_api_service.g.dart sẽ được tạo ra

    Nói thêm về: Chuyển đổi JSON format sang Dart file

    Có hai cách dùng đển chuyển Json format sang dart file. Những source trong mục này , chỉ để dùng diễn giải không sử dụng trong project.

    Cách 1: Manual Serialization

    Đây là các mà chúng ta vẫn hay làm khi sử dụng http thuần với bloc, sử dụng các hàm ví dụ như fromJson, dưới đây là ví dụ :

    Tạo file post.dart , có nội dung như sau :

    Cách 2 – Automatic Serialization

    Trước khi để sử dụng cách này thì bạn cần khai báo các thư viện như json_annotation và json_serializable như ở trên.

    Bạn thấy một số lỗi ?
    Tiếp tuc chạy dòng lệnh trong mục terminal : flutter pub run build_runner build
    Trong quá trình chạy bạn thấy báo lỗi : Missing “part ‘post.g.dart’;”.

    Thêm khai báo đó: part ‘post.g.dart’; và tiếp tục chạy tiếp dòng lệnh trên : flutter pub run build_runner build

    Nhận xét : Phương pháp automatic serialization dùng cho các dự án trung bình và lớn

    Xây dựng UI
    Trong file main.dart, bạn có thể dùng đoạn code bên dưới :

    Dưới đây là kết quả :

    Kết luận : Retrofit là khái niệm ban đầu được dùng cho Android, tuy nhiên khi dùng trên Flutter framework, nó cũng phát huy tác dụng trên iOS. Sử dụng retrofit có rất nhiều ưu việt, nó phù hợp với các dự án trung bình và lớn bởi tính tiện dụng của nó.

    Cảm ơn các bạn đã đọc bài viết về Retrofit Flutter của tôi !

  • Firebase dùng trong Flutter (Phần 2)

    Cloud Firestore

    Cloud Firestore là gì?

    Firestore là một cơ sở dữ liệu đám mây NoSQL linh hoạt, có thể mở rộng để lưu trữ và đồng bộ dữ liệu. Nó giữ cho dữ liệu của bạn được đồng bộ hóa trên các ứng dụng khách thông qua trình nghe thời gian thực và cung cấp hỗ trợ ngoại tuyến để bạn có thể tạo các ứng dụng đáp ứng hoạt động bất kể độ trễ mạng hoặc kết nối Internet.

    Thêm package depedentcy vào ứng dựng

    • Từ root của ứng dụng, chạy đoạn command dưới đây:

    flutter pub add cloud_firestore

    • Sau khi hoàn tất, hãy xây dựng lại ứng dụng Flutter của bạn.

    flutter run

    • Gọi thư viện vào trong Dart code:

    import ‘package:cloud_firestore/cloud_firestore.dart’;

    Khởi tạo:

                    FirebaseFirestore firestore = FirebaseFirestore.instance;

    Document & Query Snapshots

    Khi thực hiện một truy vấn, Firestore trả về một QuerySnapshot hoặc một DocumentSnapshot.

    a. QuerySnapshot

    QuerySnapshot được trả về từ truy vấn bộ sưu tập và cho phép bạn kiểm tra bộ sưu tập, chẳng hạn như có bao nhiêu tài liệu tồn tại bên trong nó, cấp quyền truy cập vào các tài liệu trong bộ sưu tập, xem bất kỳ thay đổi nào kể từ truy vấn cuối cùng và hơn thế nữa.

    b. DocumentSnapshot

    DocumentSnapshot được trả về từ một truy vấn hoặc bằng cách truy cập trực tiếp vào tài liệu. Ngay cả khi không có tài liệu nào tồn tại trong cơ sở dữ liệu, ảnh chụp nhanh sẽ luôn được trả về.

    c. Một số Query.

    Filter: Dựa theo method where() để lọc dữ liệu theo trường.

    Limiting: Để giới hạn dự liệu trả về sử dụng method limit().

    Ordering: Sự dụng method oderby().

    Start & End Cursors: Để bắt đầu và / hoặc kết thúc một truy vấn tại một điểm cụ thể trong một tập hợp, bạn có thể chuyển một giá trị cho các phương thức startAt, endAt, startAfter hoặc endBefore.

    Updating documents:

    Đôi khi bạn có thể muốn cập nhật một tài liệu, thay vì thay thế tất cả dữ liệu. Phương thức đặt ở trên thay thế mọi dữ liệu hiện có trên DocumentReference nhất định. Nếu bạn muốn cập nhật tài liệu thay thế, hãy sử dụng phương pháp cập nhật:

    Removing Data

    Collections & Documents

    Firestore lưu trữ dữ liệu trong ” documents”, được chứa trong ” collections”. Tài liệu cũng có thể chứa các bộ sưu tập lồng nhau. Ví dụ: mỗi người dùng của chúng tôi sẽ có ” documents” của riêng họ được lưu trữ bên trong collection “users”. Phương pháp thu thập cho phép chúng ta tham chiếu một tập hợp trong mã của chúng ta.

    Ví dụ:

    Đọc dữ liệu.

    Để đọc một bộ sưu tập hoặc tài liệu một lần, hãy gọi phương thức Query.get hoặc DocumentReference.get. Trong ví dụ dưới đây, FutureBuilder được sử dụng để giúp quản lý trạng thái của yêu cầu:

    Cloud Storage

    Cloud Storage là gì?

    Cloud Storage được thiết kế để giúp bạn nhanh chóng, dễ dàng lưu trữ và phục vụ nội dung do người dùng tạo, chẳng hạn như ảnh và video.

    Thêm package depedentcy vào ứng dựng

    • Từ root của ứng dụng, chạy đoạn command dưới đây:

    flutter pub add flutter_storage

    • Sau khi hoàn tất, hãy xây dựng lại ứng dụng Flutter của bạn.

    flutter run

    • Gọi thư viện vào trong Dart code:

    import ‘package:cloud_firestore/ firebase_storage.dart;

    Upload file lên

    Upload và lấy ảnh:

    Delete a File

    Tổng kết:

    Trên đây là 1 số chia sẻ về Firebase dùng trong Flutter mong có thể giúp đỡ mọi người.

    Author: DuongVT19

  • Animation trong Flutter: Các loại animation và tìm hiểu chi tiết về Implicit Animations

    Animation trong Flutter: Các loại animation và tìm hiểu chi tiết về Implicit Animations

    Animation là một khái niệm rất mạnh mẽ và quan trọng trong Flutter. Chúng ta không thể tưởng tượng bất kỳ ứng dụng di động nào không có hình ảnh động. Khi bạn chạm vào một nút hoặc chuyển từ trang này sang trang khác, tất cả đều là hình ảnh động. Ảnh động nâng cao trải nghiệm người dùng và làm cho các ứng dụng tương tác hơn.

    Các loại animation trong Flutter

    1. Implicit Animation: Implicit Animation là những animation dựa vào bạn để cung cấp giá trị cho thuộc tính mà bạn muốn tạo hoạt ảnh cho widget. Flutter sẽ điều khiển các quá trình chuyển đổi và vòng đời của hoạt ảnh cho bạn.
    2. Explicit Animation: Những animation này yêu cầu bạn kiểm soát đặc biệt vòng đời tổng thể của hoạt ảnh. Điều đó có nghĩa là bạn kiểm soát cách thức và thời điểm nó bắt đầu? làm thế nào nó chuyển đổi? và nó kết thúc như thế nào?
    3. Animation với CustomPainter: Animation với CustomPainter giống như vẽ trên canvas, nơi bạn yêu cầu công cụ Flutter vẽ thứ gì đó, cung cấp các bước cần thiết để vẽ nó trên canvas và kiểm soát quá trình vẽ.
    4. Sử dụng package bên ngoài và công cụ của bên thứ ba: Nếu những gì bạn muốn tạo có vẻ khó thực hiện với code hoặc nếu animation của bạn liên quan đến việc sử dụng SVG và vectơ thì bạn có thể sử dụng một số package bên ngoài và công cụ của bên thứ ba như Rive và Lottie để chúng.

    Implicit Animations

    Nếu animation của bạn chỉ làm một việc đó là hoạt ảnh chuyển từ giá trị này sang giá trị khác và là một widget thì bạn nên sử dụng các implicit animation. Implicit animations cung cấp cách dễ nhất và nhanh nhất để bắt đầu với hoạt ảnh trong Flutter.

    Hãy xem ví dụ về nó có thể trông như thế nào

    Hmmm, AnimatedContainer ở đó là gì? Đoán xem, nó là cái gì! Trong Flutter, chúng ta cũng được cung cấp một số implicit animation được đóng gói sẵn mà chúng ta có thể sử dụng. Chúng được gọi là các widget AnimatedFoo. Nơi foo đại diện cho thuộc tính bạn muốn tạo hoạt ảnh. Bất cứ khi nào bạn đặt một giá trị mới, họ sẽ xây dựng lại với quá trình chuyển đổi từ giá trị cũ sang giá trị mới. Bạn có thể đặt thời lượng cho hoạt ảnh và đường cong để quá trình chuyển đổi diễn ra. Ngoài ra còn có một số thông số khác mà bạn có thể sử dụng. Thật thú vị đúng không! Trong widget này chúng ta có

    • AnimatedOpacity: Bạn có thể sử dụng điều này để tạo hoạt ảnh cho độ mờ của đối tượng một cách ngầm định.
    • AnimatedPadding: Một cách hay để tạo hiệu ứng cho vùng đệm xung quanh bất kỳ tiện ích nào để tạo hiệu ứng lối vào mượt mà nếu trộn với độ mờ.
    • AnimatedList: Để tạo hiệu ứng chèn và xóa các mục khỏi danh sách.
    • AnimatedIcon: Đây là một widget khá tiện dụng nếu bạn đang tìm kiếm một số hình ảnh động nút đẹp mắt nhanh chóng để thêm vào như biểu tượng bánh hamburger thay đổi thành dấu chéo khi nhấp vào.

    “Làm việc với một số AnimatedFoo như AnimatedIcon này đòi hỏi sự hiểu biết về cách sử dụng AnimationControllers với tweens mà chúng ta sẽ nói đến trong Explicit Animations.”

    Bây giờ bạn đã hiểu về một số Implicit Animation tạo trước, điều đó thật tuyệt! Đây là một cách tốt để bắt đầu nhưng điều gì sẽ xảy ra nếu bạn không tìm thấy bất kỳ AnimatedFoo nào cho thuộc tính bạn muốn tạo hoạt ảnh?

    TweenAnimationBuilder

    Đối với điều này, chúng ta có TweenAnimationBuilder, đây là một cách để xây dựng các Implicit Animation tùy chỉnh của bạn với nhiều quyền kiểm soát hơn đối với chúng.

    Hãy xem chúng trong ví dụ sau

    Ở đây, chúng ta chuyển một đối tượng tween đến TweenanimationBuilder chứa các giá trị bắt đầu và kết thúc của animation. Những đối tượng tween ở đây là gì? Đối tượng Tween đại diện cho tập hợp các giá trị cho một thuộc tính mà bạn muốn tạo hoạt ảnh. Bất cứ khi nào giá trị tween thay đổi, trình tạo sẽ được gọi và tiện ích con bên dưới nó được xây dựng lại với giá trị mới. Khi sử dụng TweenAnimationBuilder, bạn không có quyền kiểm soát thời điểm hoạt ảnh bắt đầu, nó sẽ bắt đầu ngay sau khi widget được kích hoạt. Và một điều thú vị nữa là chúng ta không cần một widget trạng thái cho việc này. Tất cả những gì được quản lý bởi chính TweenAnimationBuilder.

    Đó là hầu hết những điều bạn cần biết khi bắt đầu với implicit animation trong Flutter. Cảm ơn vì đã đọc!

  • Shared Preferences trong Flutter

    [FLUTTER] Shared Preferences trong Flutter

    Để lưu trữ các dữ liệu ở local trong ứng dụng Flutter, ngoài cách lưu bằng sqlite, chúng ta còn thể lưu dữ liệu vào Shared Preferences

    1. Sơ lược về Shared Preferences trong Flutter

    • Dùng để lưu những tập dữ liệu nhỏ dưới dạng key-value
    • Các loại dữ liệu có thể lưu như là int, double, bool, String and List<String>
    • Các dữ liệu được lưu lại trong một file .xml và được lưu vào trong bộ nhớ đệm của máy
    • Các dữ liệu chúng ta có thể dùng để lưu như là các thông số về Settings, token,, …

    2. Cách sử dụng

    • Thêm thư viện vào trong file pubspect.yaml:
    shared_preferences: ^2.0.13

    Vì các hàm xử lý lưu dữ liệu trong shared_preferences đều là các hàm Future, nên chúng ta cần dùng await để gọi:

    • Hàm lưu dữ liệu
    // Obtain shared preferences.
    final prefs = await SharedPreferences.getInstance();
    
    // Save an integer value to 'counter' key. 
    await prefs.setInt('counter', 10);
    // Save an boolean value to 'repeat' key. 
    await prefs.setBool('repeat', true);
    // Save an double value to 'decimal' key. 
    await prefs.setDouble('decimal', 1.5);
    // Save an String value to 'action' key. 
    await prefs.setString('action', 'Start');
    // Save an list of strings to 'items' key. 
    await prefs.setStringList('items', <String>['Earth', 'Moon', 'Sun']);
    • Hàm đọc dữ liệu
    // Try reading data from the 'counter' key. If it doesn't exist, returns null.
    final int? counter = prefs.getInt('counter');
    // Try reading data from the 'repeat' key. If it doesn't exist, returns null.
    final bool? repeat = prefs.getBool('repeat');
    // Try reading data from the 'decimal' key. If it doesn't exist, returns null.
    final double? decimal = prefs.getDouble('decimal');
    // Try reading data from the 'action' key. If it doesn't exist, returns null.
    final String? action = prefs.getString('action');
    // Try reading data from the 'items' key. If it doesn't exist, returns null.
    final List<String>? items = prefs.getStringList('items');
    • Nếu chúng ta muốn xóa bỏ dữ liệu đã được lưu
    // Remove data for the 'counter' key. 
    final success = await prefs.remove('counter');

    Tài liệu tham khảo: shared_preferences | Flutter Package (pub.dev)

    Author: LamNT59

  • Firebase dùng trong Flutter (Phần 1):

    1. Tổng quan.

    Firebase là một nền tảng để phát triển ứng dụng di động và trang web, bao gồm các API đơn giản và mạnh mẽ mà không cần backend hay server.

    Lợi ích của Firebase là gì? Firebase còn giúp các lập trình viên rút ngắn thời gian triển khai và mở rộng quy mô của ứng dụng mà họ đang phát triển. Firebase là dịch vụ cơ sở dữ liệu hoạt động trên nền tảng đám mây – cloud.

    Kèm theo đó là hệ thống máy chủ cực kỳ mạnh mẽ của Google. Chức năng chính là giúp người dùng lập trình ứng dụng bằng cách đơn giản hóa các thao tác với cơ sở dữ liệu.

    Cụ thể là những giao diện lập trình ứng dụng API đơn giản. Mục đích nhằm tăng số lượng người dùng và thu lại nhiều lợi nhuận hơn.

    Đặc biệt, còn là dịch vụ đa năng và bảo mật cực tốt. Firebase hỗ trợ cả hai nền tảng Android và IOS. Và Flutter framework cũng hỗ trợ đa nền tảng đặc biệt là phát triển ứng dựng mobile cho cả Android và IOS từ một source code. Vì vậy, tôi muốn trình bày việc sử dụng Firebase trong Flutter.

    2. Firebase Authentication.

    2.1. Thêm Firebase Authentication vào ứng dựng.

    1. Từ root của ứng dụng, chạy đoạn command dưới đây:

    flutter pub add firebase_auth

    • Sau khi hoàn tất, hãy xây dựng lại ứng dụng Flutter của bạn.

    flutter run

    • Gọi thư viện vào trong Dart code:

    import ‘package:firebase_auth/firebase_auth.dart’;

    2.2. Kiểm tra các trạng thái hiện tại.

    Firebase Auth cung cấp nhiều phương pháp và tiện ích cho phép bạn tích hợp xác thực an toàn vào ứng dụng Flutter mới hoặc hiện có của mình. Trong nhiều trường hợp, bạn sẽ cần biết về trạng thái xác thực của người dùng, chẳng hạn như họ đã đăng nhập hay đã đăng xuất.

    Có 3 phương thức để lắng nghe các trạng thái thay đổi xác thực:

    a. authStateChanges()

    Các sự kiện sẽ kích hoạt khi xảy ra những điều sau:

    • Ngay sau khi người nghe đã được đăng ký.
    • Khi người dùng đã đăng nhập.
    • Khi người dùng hiện tại đã đăng xuất.

    b. idTokenChanges()

    Các sự kiện sẽ kích hoạt khi xảy ra những điều sau:

    • Ngay sau khi người nghe đã được đăng ký.
    • Khi người dùng đã đăng nhập.
    • Khi người dùng hiện tại đã đăng xuất.
    • Khi có sự thay đổi trong mã thông báo của người dùng hiện tại.

    c. userChanges()

    Các sự kiện sẽ kích hoạt khi xảy ra những điều sau:

    • Ngay sau khi người nghe đã được đăng ký.
    • Khi người dùng đã đăng nhập.
    • Khi người dùng hiện tại đã đăng xuất.
    • Khi có sự thay đổi trong mã thông báo của người dùng hiện tại.

    Chú ý: idTokenChanges(), userChanges() & authStateChanges() sẽ không kích hoạt nếu bạn cập nhật Hồ sơ người dùng bằng SDK quản trị Firebase. Bạn sẽ phải buộc tải lại bằng cách sử dụng FirebaseAuth.instance.currentUser.reload() để truy xuất hồ sơ Người dùng mới nhất.

    idTokenChanges(), userChanges() & authStateChanges() cũng sẽ không kích hoạt nếu bạn tắt hoặc xóa Người dùng bằng SDK quản trị Firebase hoặc bảng điều khiển Firebase. Bạn sẽ phải buộc tải lại bằng FirebaseAuth.instance.currentUser.reload(), điều này sẽ gây ra trường hợp người dùng bị vô hiệu hóa hoặc không tìm thấy ngoại lệ mà bạn có thể bắt và xử lý trong code ứng dụng của mình.

    2.3. Quản lý Users trong Firebase.

    a. Tạo tài khoản.

    Sử dụng phương thức createUserWithEmailAndPassword():

    b. Đăng nhập với email.

    Sử dụng phương thức: signInWithEmailAndPassword():

    c. Lấy thông tin user hiện tại.

    d. Lấy thông tin được cung cấp cụ thể của người dùng.

    e. Cập nhật thông tin người dùng.

    Sử dụng phương thức update().

    f. Xóa người dùng hiện tại.

    Sử dụng phương thức delete()

    Trên đây là những kiến thức cơ bản về Firebase ứng dụng trong Flutter, ở phần tiếp theo tôi sẽ trình biết tiếp về ứng Firestore và Sotorage.

  • [Flutter]Tạo Widget với Android Native bằng Platform Views

    [Flutter]Tạo Widget với Android Native bằng Platform Views

    Một ví dụ về tạo 2 widget được triển khai dưới Android Native

    Dưới Native

    Đầu tiên, chúng ta sẽ tạo 2 class FirstWidget.kt và SecondWidget.kt:

    • FirstWidget.kt : Sử dụng file .xml
    
    import android.content.Context
    import android.view.LayoutInflater
    import android.view.View
    import io.flutter.plugin.platform.PlatformView
    
    internal class FirstWidget(context: Context, id: Int, creationParams: Map<String?, Any?>?) : PlatformView {
        private val view: View
    
        override fun getView(): View {
            return view
        }
    
        init {
            view = LayoutInflater.from(context).inflate(R.layout.first_widget, null)
        }
    
        override fun dispose() {
        }
    }
    • first_widget.xml
    <?xml version="1.0" encoding="utf-8"?>
    <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior"
        tools:context=".MainActivity"
        tools:showIn="@layout/first_widget">
    
        <TextView
            android:id="@+id/first_widget_text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="FirstWidget from Android!"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
    
    </androidx.constraintlayout.widget.ConstraintLayout>
    • SecondWidget.kt: 1 cách khác để tạo view
    import android.content.Context
    import android.graphics.Color
    import android.view.View
    import android.widget.TextView
    import io.flutter.plugin.platform.PlatformView
    
    internal class SecondWidget(context: Context, id: Int, creationParams: Map<String?, Any?>?) : PlatformView {
        private val textView = TextView(context)
    
        override fun getView(): View {
            return textView
        }
    
        override fun dispose() {}
    
        init {
            textView.textSize = 20f
            textView.setBackgroundColor(Color.rgb(255, 255, 255))
            textView.text = "Rendered on a native Android view (id: $id)"
        }
    }

    Tạo 2 class FirstWidgetFactory.kt và SecondWidgetFactory.kt:

    • FirstWidgetFactory.kt
    import android.content.Context
    import io.flutter.plugin.common.StandardMessageCodec
    import io.flutter.plugin.platform.PlatformView
    import io.flutter.plugin.platform.PlatformViewFactory
    
    class FirstWidgetFactory : PlatformViewFactory(StandardMessageCodec.INSTANCE) {
        override fun create(context: Context, viewId: Int, args: Any?): PlatformView {
            val creationParams = args as Map<String?, Any?>?
            return FirstWidget(context, viewId, creationParams)
        }
    }
    • SecondWidgetFactory.kt
    import android.content.Context
    import io.flutter.plugin.common.StandardMessageCodec
    import io.flutter.plugin.platform.PlatformView
    import io.flutter.plugin.platform.PlatformViewFactory
    
    class SecondWidgetFactory : PlatformViewFactory(StandardMessageCodec.INSTANCE) {
        override fun create(context: Context, viewId: Int, args: Any?): PlatformView {
            val creationParams = args as Map<String?, Any?>?
            return SecondWidget(context, viewId, creationParams)
        }
    }

    Tại MainActivity.kt:

    import io.flutter.embedding.android.FlutterActivity
    import io.flutter.embedding.engine.FlutterEngine
    import io.flutter.plugins.GeneratedPluginRegistrant
    
    class MainActivity : FlutterActivity() {
    
        override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
            GeneratedPluginRegistrant.registerWith(flutterEngine)
            flutterEngine
                    .platformViewsController
                    .registry
                    .registerViewFactory("com.example.flutter_app_demo1.FirstWidgetPlugin", FirstWidgetFactory())
            flutterEngine
                    .platformViewsController
                    .registry
                    .registerViewFactory("com.example.flutter_app_demo1.SecondWidgetPlugin", SecondWidgetFactory())
        }
    
    }

    Về phần Dart

    Tạo 2 file first_widget.dart và second_widget.dart:

    • first_widget.dart
    import 'package:flutter/foundation.dart';
    import 'package:flutter/gestures.dart';
    import 'package:flutter/material.dart';
    import 'package:flutter/rendering.dart';
    import 'package:flutter/services.dart';
    
    
    class FirstWidget extends StatefulWidget {
      const FirstWidget({
        Key? key,
      }) : super(key: key);
    
    
      @override
      State<StatefulWidget> createState() => _FirstWidgetState();
    }
    
    class _FirstWidgetState extends State<FirstWidget> {
       String viewType = 'com.example.flutter_app_demo1.FirstWidgetPlugin';
       Map<String, dynamic> creationParams = <String, dynamic>{};
      @override
      Widget build(BuildContext context) {
        if (defaultTargetPlatform == TargetPlatform.android) {
          return SizedBox(
            width: 200,
            child: PlatformViewLink(
              viewType: viewType,
              surfaceFactory:
                  (BuildContext context, PlatformViewController controller) {
                return AndroidViewSurface(
                  controller: controller as AndroidViewController,
                  gestureRecognizers:  const <Factory<OneSequenceGestureRecognizer>>{},
                  hitTestBehavior: PlatformViewHitTestBehavior.opaque,
                );
              },
              onCreatePlatformView: (PlatformViewCreationParams params) {
                return PlatformViewsService.initSurfaceAndroidView(
                  id: params.id,
                  viewType: viewType,
                  layoutDirection: TextDirection.ltr,
                  creationParams: creationParams,
                  creationParamsCodec: const StandardMessageCodec(),
                  onFocus: () {
                    params.onFocusChanged(true);
                  },
                )
                  ..addOnPlatformViewCreatedListener(params.onPlatformViewCreated)
                  ..create();
              },
            ),
          );
        }
        return const Text('iOS platform version is not implemented yet.');
      }
    
    }
    • second_widget.dart
    import 'package:flutter/foundation.dart';
    import 'package:flutter/gestures.dart';
    import 'package:flutter/material.dart';
    import 'package:flutter/rendering.dart';
    import 'package:flutter/services.dart';
    
    class SecondWidget extends StatefulWidget {
      const SecondWidget({
        Key? key,
      }) : super(key: key);
    
      @override
      State<StatefulWidget> createState() => _SecondWidgetState();
    }
    
    class _SecondWidgetState extends State<SecondWidget> {
      String viewType = "com.example.flutter_app_demo1.SecondWidgetPlugin";
      Map<String, dynamic> creationParams = <String, dynamic>{};
      @override
      Widget build(BuildContext context) {
        if (defaultTargetPlatform == TargetPlatform.android) {
          return PlatformViewLink(
            viewType: viewType,
            surfaceFactory:
                (BuildContext context, PlatformViewController controller) {
              return AndroidViewSurface(
                controller: controller as AndroidViewController,
                gestureRecognizers:  const <Factory<OneSequenceGestureRecognizer>>{},
                hitTestBehavior: PlatformViewHitTestBehavior.opaque,
              );
            },
            onCreatePlatformView: (PlatformViewCreationParams params) {
              return PlatformViewsService.initSurfaceAndroidView(
                id: params.id,
                viewType: viewType,
                layoutDirection: TextDirection.ltr,
                creationParams: creationParams,
                creationParamsCodec: const StandardMessageCodec(),
                onFocus: () {
                  params.onFocusChanged(true);
                },
              )
                ..addOnPlatformViewCreatedListener(params.onPlatformViewCreated)
                ..create();
            },
          );
        }
        return const Text('iOS platform version is not implemented yet.');
      }
    
    }
    

    Sau đó gọi lại 2 Widget vừa rồi tại main.dart

    @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: const Text('Flutter PlatformView Example'),
          ),
          body: Column(
            mainAxisSize: MainAxisSize.min,
            mainAxisAlignment: MainAxisAlignment.spaceAround,
            children: const <Widget>[
              Card(
                child: SizedBox(
                  height: 200,
                  child: FirstWidget(),
                ),
              ),
              Card(
                child: SizedBox(
                  height: 200,
                  child: SecondWidget(),
                ),
              ),
            ],
          ),
        );
      }

    PlatformView

    PlatformView là một tính năng Flutter cần thực hiện để hiển thị Native-UIs toàn diện trên Android View / UIKitView.

    Nếu bạn muốn biết thêm thông tin về PlatformView, hãy xem tài liệu chính thức:

  • [FLUTTER] MỘT SỐ WIDGET HỮU ÍCH TRONG FLUTTER (PHẦN CUỐI)

    [FLUTTER] MỘT SỐ WIDGET HỮU ÍCH TRONG FLUTTER (PHẦN CUỐI)

    Ở phần cuối này mình sẽ giới thiệu cho anh em nốt những widget hay ho mà mình tìm hiểu được.
    Anh em có thể đọc lại 2 phần trước ở đây nhé:

    Phần 1
    Phần 2

    Bắt đầu luôn nào!!!

    1. RichText

    Có lúc nào anh em muốn viết một dòng chữ nhưng các phần trong đó lại có định dạng khác nhau? Ví dụ có thể kể ra là một phần của đoạn văn bản có thể click vào như ảnh dưới đây:

    Anh em có thể nghĩ đến việc sử dụng Row với 2 Text con bên trong, nhưng có vẻ hơi cồng kềnh nhỉ? Và đó chính là lúc RichText phát huy tác dụng của mình. Thay vì viết như này:

            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                const Text("Not a user?"),
                TextButton(
                  onPressed: () {},
                  child: const Text(
                    "Sign up",
                    style: TextStyle(decoration: TextDecoration.underline),
                  ),
                )
              ],
            ),

    Chúng ta có thể viết như này để dễ hiểu hơn (về mặt logic, code thì cũng same nhau à :D):

            RichText(
              text: TextSpan(
                text: "Not a user? ",
                style: const TextStyle(color: Colors.black),
                children: <TextSpan>[
                  TextSpan(
                      text: "Signup",
                      style: const TextStyle(
                          color: Colors.blue, decoration: TextDecoration.underline),
                      recognizer: TapGestureRecognizer()..onTap = () {})
                ],
              ),
            ),

    RichText sẽ nhận vào một text là InlineSpan, ở đây ta sẽ sử dụng TextSpan. Ở trong TextSpan lại có các children là InlineSpan, cho nên ta có thể nối nhiều đoạn text lại với nhau, mỗi đoạn có thể có các style riêng biệt.

    2. SafeArea

    Các thiết bị di động ngày nay đã khác xưa rất nhiều, không chỉ đơn giản là một màn hình hình chữ nhật nữa. Chúng ta có màn hình “tai thỏ”, “nốt ruồi” rồi thậm chí là “giọt nước”. Các thiết kế phức tạp trên khiến người lập trình cũng phải để ý khi tạo ra các ứng dụng mới.

    Và để tránh nội dung của ứng dụng bị che khuất bởi các vị trí “nhạy cảm” kia, ở Flutter chúng ta có SafeArea.

    So sánh khi không sử dụng / sử dụng SafeArea

    Ở ảnh trên ta thấy, khi sử dụng SafeArea, AppBar sẽ không đè lên phần status bar của máy nữa (AppBar màu xanh dương), rất phù hợp khi thiết bị có những “nốt ruồi” hay “tai thỏ”.

    thông thường ta sẽ wrap cả Scaffold ở trong widget SafeArea để đảm bảo không bị mất nội dung.

    3. SelectableText

    Chắc mình sẽ không cần phải nói nhiều về widget này vì cái tên đã thể hiện quá rõ tác dụng của nó rồi. 😀 😀

    Khi anh em muốn cho phép người dùng chọn được đoạn văn bản thì có thể sử dụng widget này.

    SelectableText

    À mà anh em có thể kết hợp widget này với RichText ở bên trên bằng cách sử dụng SelectableText.rich() nhé, thật tiện lợi phải không ^^

    Tổng kết

    Vậy là qua 3 phần mình đã giới thiệu đến anh em một số widget mà mình cảm thấy hữu ích trong quá trình làm việc với Flutter. Do kiến thức còn hạn chế, khả năng viết bài cũng non nớt nên nếu có lỗi sai thì mong anh em hãy comment góp ý để mọi người có thể nâng cao kiến thức của mình nhé. Cảm ơn anh em đã theo dõi 😀 😀

  • [Flutter] Kiến trúc MVVM

    [Flutter] Kiến trúc MVVM

    Kiến trúc MVVM là gì?

    MVVM (Model View ViewModel) là một kiến ​​trúc thiết kế tạo điều kiện cho việc chia nhỏ các nguyên tắc thiết kế, thường được gọi là sự tách biệt phát triển của những người nghiệp dư về công nghệ, thành các phần riêng biệt của GUI. Tư tưởng cơ bản đằng sau việc triển khai các phương pháp hay nhất về kiến ​​trúc ứng dụng dành cho thiết bị di động là xây dựng “View Model” có thể đại diện cho dữ liệu thông qua một chế độ xem.

    Lý do tại sao phần lớn các nhà phát triển, nói đến thiết kế ứng dụng Android hoặc iOS, ưa thích MVVM là vì nó tách biệt Activity và Fragment  khỏi logic. Để viết một codebase linh hoạt, các nhà phát triển ứng dụng bắt buộc phải xây dựng một lớp View-Model có thể được sử dụng bởi một số ‘Views’ nhất định. Hơn nữa, kiến ​​trúc MVVM cũng giúp các nhà phát triển tự động hóa việc truyền các sửa đổi bên trong View-Model tới Views.

    Ba thành phần quan trọng của kiến ​​trúc MVVM trong Flutter

    Mẫu thiết kế MVVM được quản lý bởi ba thành phần chính là Model, View và ViewModel . Các yếu tố chính này giúp thiết lập một khối cho toàn bộ cơ sở mã của mẫu thiết kế MVVM. Mặc dù mỗi thành phần có vai trò và chức năng khác nhau, nhưng sự tương tác logic giữa các thành phần này trong quá trình phát triển ứng dụng đóng một vai trò quan trọng. Trong kiến ​​trúc MVVM, khung nhìn tương tác với mô hình khung nhìn để liên kết dữ liệu và mô hình khung nhìn giao tiếp với mô hình. Để hiểu tại sao MVVM lại quan trọng đối với dự án ứng dụng của bạn, điều cần thiết là phải chăm chỉ nhận thức từng yếu tố. Vì vậy, chúng ta hãy bắt đầu.

    1. Model

    Vai trò chính của Model trong MVVM là thực hiện logic nghiệp vụ trong mẫu thiết kế mà chỉ hoạt động dựa trên nguồn dữ liệu cần thiết trong một hoạt động. Hiểu theo cách khác, phần tử model của mẫu kiến ​​trúc MVVM được sử dụng để đại diện cho dữ liệu thời gian thực cuối cùng sẽ được sử dụng trong phát triển ứng dụng.

    Điều tốt nhất về model là hiển thị sự tương tác giữa tất cả các thành phần hoàn toàn bằng cách tìm nạp dữ liệu từ cơ sở dữ liệu phòng. Nếu chúng ta phải xác định model trong một câu duy nhất, chúng ta có thể nói – nó là một phần tử lưu trữ dữ liệu và logic liên quan của kiến ​​trúc.

    2. View

    View là viết tắt của các thành phần UI như HTML, CSS. Trong MVVM, View chịu trách nhiệm về lớp trình bày trong mẫu thiết kế và là một điểm vào ứng dụng. Khi chúng ta nói về lợi ích của kiến ​​trúc MVVM, các thuộc tính của view đã được ca ngợi. Có một tập hợp phân cấp được duy trì giữa mỗi mô hình MVVM trong khi thể hiện sự tương tác. Ví dụ: View không bao giờ tương tác trực tiếp với Model mà thông qua ViewModel. Tất cả dữ liệu được thu thập bởi Model giúp tạo dữ liệu bản trình bày cho View. View thực thi logic thiết kế UI-UX và yêu cầu mô hình gửi lại đầu ra cho người dùng.

    3. ViewModel

    Ngoài việc làm trung gian giữa các thành phần Model và View, ViewModel triển khai dữ liệu và các lệnh được kết nối với View trong kiến ​​trúc MVVM để thông báo cho phần tử sau về các thay đổi trạng thái. Có một ví dụ ViewModel Android để thực hiện các công việc khác nhau như tạo lớp con hoặc thêm phần phụ thuộc, v.v. ViewModels có thể được liên kết với một hoặc nhiều mô hình.
    Về cơ bản, vai trò của ViewModel trong kiến trúc MVVM là hỗ trợ trạng thái của View và hoạt động như một lớp logic của toàn bộ cộng đồng kiến ​​trúc MVVM. Sẽ không sai khi trích dẫn ViewModel là phần tích hợp của tất cả những gì làm cho Mô hình duy trì dữ liệu thực tế và phần View đóng gói dữ liệu cập nhật giữ bộ điều khiển như một cổng giữa chúng.

    Lợi ích của kiến ​​trúc MVVM dành cho ứng dụng Android và iOS

    Mục tiêu cơ bản của mô hình kiến ​​trúc ứng dụng dành cho thiết bị di động trong phát triển ứng dụng là củng cố các chiến lược phát triển ứng dụng dành cho thiết bị di động với nhiều kỹ thuật dựa trên các tiêu chuẩn của ngành và nhà cung cấp cụ thể để cuối cùng thúc đẩy việc xây dựng ứng dụng, Android hoặc iOS. Một câu hỏi khiến hầu hết các chủ dự án không hài lòng là – Tại sao MVVM lại quan trọng đối với ứng dụng của bạn? Nói cách khác, câu hỏi đề xuất – “điều kỳ diệu mà mẫu thiết kế này có thể làm với ứng dụng của bạn”.

    MVVM, một biến thể viết tắt của Model View ViewModel, nhằm mục đích tách ứng dụng thành ba thành phần hợp lý và sau đó xử lý các khía cạnh phát triển cụ thể của ứng dụng. Mặc dù thị trường có rất nhiều mẫu kiến ​​trúc cải thiện hiệu suất ứng dụng và khả năng của thiết bị, MVVM đặc biệt tập trung vào tầm quan trọng của kiến ​​trúc giải pháp mang lại trải nghiệm UI tốt hơn cho người dùng. Bên cạnh việc quản lý và trình bày các đối tượng dữ liệu, kiến ​​trúc MVVM có rất nhiều lợi ích để cung cấp, một số lợi ích được liệt kê dưới đây.

    1. Khả năng tái sử dụng

    Khi hiểu được toàn bộ khái niệm về việc giới thiệu kiến ​​trúc MVVM trong quá trình thiết kế ứng dụng, có thể xác định đây là mô hình giúp các nhà phát triển phân biệt rõ ràng giữa các ứng dụng được kết hợp lỏng lẻo và kết hợp chặt chẽ. Khớp nối là yếu tố phụ thuộc của thiết kế trong ứng dụng và có những thiết kế kiến ​​trúc có khớp nối chặt chẽ, điều này cuối cùng làm tăng chi phí bảo trì phát triển trang web và giảm khả năng tái sử dụng của thành phần. Kiến trúc MVVM đi kèm với khớp nối lỏng lẻo để đạt được sự phân tách trách nhiệm và nâng cao mức độ khớp nối lỏng lẻo. Mặt khác, yếu tố khả năng tái sử dụng cho phép các mã được sử dụng để xây dựng các mẫu thiết kế trong các ứng dụng khác.

    2. Thúc đẩy phát triển mã độc lập

    MVVM là một mô hình kiến ​​trúc độc lập cung cấp dữ liệu dưới dạng đầu ra thông qua View. Toàn bộ cơ sở mã của mẫu MVVM được tạo ra theo cách khắc phục các trục trặc phổ biến mà hầu hết các mẫu kiến ​​trúc trở thành nạn nhân của nó. Với ba thành phần chính của nó, kiến ​​trúc MVVM truy xuất và lưu giữ các đối tượng thông qua một dịch vụ. Dù nói đến thiết kế mô hình kiến ​​trúc MVVM Android Architecture hoặc iOS , mô hình MVVM thúc đẩy sự phát triển độc lập của ứng dụng. Vì kiến ​​trúc mã và đơn giản hóa mẫu thiết kế là mục tiêu cốt lõi của các nhà phát triển, phương pháp tiếp cận mẫu thiết kế MVVM sẽ giải quyết một số vấn đề tồn tại trong khuôn khổ thiết kế của một ứng dụng và xem xét tất cả các khía cạnh quan trọng mang lại kết quả tuyệt vời ở phần cuối của dự án.

    3. Nâng cao khả năng kiểm tra

    Mẫu thiết kế MVVM Android hoặc iOS dường như đang thu hút sự chú ý trên thị trường do các nhà phát triển có kỹ năng điều hành. Phần lớn các nhà phát triển tin rằng MVVM có thể đọc được, có thể mở rộng và có thể kiểm tra được so với các mô hình thiết kế kiến ​​trúc khác. Trong số tất cả các thành phần, ViewModel có trách nhiệm rất lớn là đại diện cho dữ liệu và khởi tạo trường hợp thử nghiệm trong mô hình kiến ​​trúc MVVM. Chính ViewModel làm cho thành phần View có thể tái sử dụng và có thể kiểm tra được, giúp cho việc khen ngợi logic nghiệp vụ kiểm thử đơn vị trở nên dễ dàng hơn. Do sự phụ thuộc của phần tử này, việc bắt đầu các trường hợp thử nghiệm trở nên ít phức tạp hơn một chút.

    4. Khả năng bảo trì

    Mặc dù một số nhà phát triển có thể thấy các chỉ số hiệu suất ứng dụng dành cho thiết bị di động và tính năng chia sẻ của kiến ​​trúc MVVM hơi khó chịu và phức tạp, nhưng khả năng bảo trì của kiến ​​trúc MVVM mang lại lợi ích cho mô hình là mạch lạc và đơn giản hóa, lưu ý các yêu cầu bổ sung. Khả năng bảo trì lồng vào nhau cung cấp khả năng mở rộng tối đa với sự phân tách ranh giới rõ ràng.
    Khả năng thay thế hoặc thêm các khối mã mới trong quá trình ứng dụng là một điều lý tưởng cần xem xét để đặt các mã trong cơ sở hạ tầng ứng dụng một cách phù hợp. Ngoài ra, tính năng ánh xạ trong kiến ​​trúc MVVM là chưa từng có. Mô hình MVVM sử dụng ánh xạ một đến nhiều giữa View và ViewModel.

  • Final và Constant trong Dart – Cách xác định Hằng số trong Dart

    Final và Constant trong Dart – Cách xác định Hằng số trong Dart

    Xin chào!. Trong bài viết này, chúng ta sẽ tim hiểu về final và constant trong dart là gì. Cách xác định constant trong Dart. Câu hỏi quan trọng nhất là Tại sao chúng ta cần final và const và mục đích của những từ khóa này là gì?

    Final Constant của dart

    Nếu bạn không bao giờ muốn thay đổi một giá trị thì hãy sử dụng các từ khóa final và const.

    Có rất nhiều trường hợp mà chúng ta không muốn thay đổi giá trị của một biến. Ví dụ, giá trị của Pi.

    const PI = 3,14;

    Hoặc có thể bạn không muốn thay đổi tên trong toàn bộ chương trình.

    final name = ”Waheed”;

    Hằng số PI sẽ chứa giá trị 3,14 và final name sẽ có giá trị ‘Waheed’ trong toàn bộ mã. Bây giờ trong cả hai trường hợp, bạn sẽ không thể thay đổi giá trị của biến PI hoặc name. Câu hỏi phổ biến đó là Sự khác biệt giữa final và const là gì.

    Sự khác biệt giữa Final và Const

    • Một biến final chỉ có thể được đặt một lần và nó chỉ được khởi tạo khi được truy cập.
      • Ở đây mấu chốt ở đây là “nó chỉ được khởi tạo chỉ khi nó được truy cập” nghĩa là bạn chỉ sử dụng được biến final trong chương trình của mình khi giá trị được khởi tạo và vị trí bộ nhớ được cấp phát. Và nếu bạn không bao giờ sử dụng biến final, giá trị sẽ không bao giờ được khởi tạo trong chương trình của bạn.
    • Một biến const hoàn toàn là final nhưng nó là một hằng số compile time
      • Nó có nghĩa là tất cả các biến const cũng là final.
      • Nó là một hằng số compile time đã biên dịch có nghĩa là nó được khởi tạo trong quá trình biên dịch. Bất cứ khi nào bạn biên dịch chương trình, giá trị của PI sẽ được khởi tạo và bộ nhớ sẽ được cấp phát. Không quan trọng bạn có đang sử dụng biến này hay không.
    • Một biến instance có thể là final nhưng không thể là const
      • Nếu bạn muốn tạo một Hằng số ở class, hãy khai báo nó là static const chứ không chỉ mỗi const.

    Bây giờ đã đến lúc làm rõ các khái niệm bằng một ví dụ thực tế.

    Chúng tôi đã xác định một biến final name và sau đó chúng tôi đang cố gắng thay đổi giá trị của biến final name nhưng chúng tôi sẽ nhận được thông báo lỗi như thế này.

    ‘error‘name’, a final variable, can only be set once.‘ Or something like ‘ cannot assign to final variable name‘

    Có nghĩa là: ‘‘Error‘name’, một biến final, chỉ có thể được đặt một lần. ‘Hoặc một cái gì đó như‘ không thể gán cho biến final name ‘’

    Bạn có thể nhận thấy khi chưa xác định kiểu dữ liệu cho tên biến. Chà, Dart hiểu nó là một Chuỗi theo giá trị nghĩa đen của nó. Bạn có thể xác định rõ ràng nó là một String nhưng nó là tùy chọn.

    Chúng ta cũng hãy xem một ví dụ về const.

    Đây là cách chúng ta định nghĩa const trong Dart.

    Có một khái niệm rất quan trọng khác cần hiểu. Hãy nhớ rằng chúng tôi đã nghiên cứu rằng ‘Một biến instance có thể là biến final nhưng không thể là const.’ Hãy làm rõ khái niệm này với sự trợ giúp của một ví dụ. Để làm được điều đó, chúng ta phải tạo một Class. Nếu bạn không quen thuộc với class là gì, xin đừng lo lắng, chúng tôi sẽ sớm đề cập đến khái niệm class. Còn bây giờ chỉ cần tiếp tục theo dõi với chúng tôi.

    Chà, trình biên dịch sẽ cung cấp cho chúng ta một lỗi tại const weight. ‘Chỉ có thể khai báo các trường static là const‘.

    Vì vậy, nếu bạn xác định một const ở mức Class thì bạn cũng phải sử dụng từ khóa static. Chúng ta sẽ đề cập đến từ khóa static là gì nhưng hiện tại, hãy nhớ rằng chúng ta không thể khai báo một biến const ở cấp độ Class một cách đơn giản. Nó phải là static const.

    Đó là một hướng dẫn rất ngắn nhưng chi tiết về final và const của dart. Chúng tôi chắc chắn rằng bây giờ bạn sẽ không bao giờ quên các khái niệm final và const. Cảm ơn vì đã theo dõi.