Tag: flutter

  • Hướng dẫn Riverpod trong Flutter (Flutter Riverpod Tutorial)

    Hướng dẫn Riverpod trong Flutter (Flutter Riverpod Tutorial)

    Hướng dẫn Riverpod trong Flutter
    (Flutter Riverpod Tutorial)

    Trong Flutter có rất nhiều cách quản lý state như Provider, Bloc, GetX, Redux,… Mỗi cách đều có những ưu nhược điểm riêng. Trong số đó, có 3 phương pháp quản lý state phổ biến hơn cả là Provider (được team Flutter của Google đề xuất sử dụng), Boc (được rất nhiều lập trình viên chuyên nghiệp khuyên dùng) và gần đây nhất là GetX được đông đảo người mới tiếp cận Flutter lựa chọn nhờ sự đơn giản, dễ sử dụng.

    Mời bạn xem danh sách video hướng dẫn quản lý trạng thái trong flutter:

    Provider có một số hạn chết nhất định và Riverpod chính là bản nâng cấp của Provider để khắc phục những hạn chế đó.

    Có thể bạn không để ý, “Riverpod” chính là các chữ cái của “Provider” được sắp xếp lại.

    Riverpod trong Flutter có gì khác Provider?

    Nhược điểm của Provider

    Theo thiết kế, Provider là một cải tiến của InheritedWidget và nó phụ thuộc vào các widget của Flutter. Bạn sẽ sử dụng các widget mặc định của Flutter xây dựng lên ứng dụng của mình.

    Việc kết hợp các Provider rất dài dòng, việc trộn lẫn giữa UI code và dependency injection khiến code rất khó đọc. (Để hiểu dependency injection mời bạn xem video sau https://www.youtube.com/watch?v=SVqHgRbwBLs)

    Hãy tưởng tượng bạn có MySecondClass phụ thuộc vào MyFirstClass.

    main.dart

    class MySecondClass {
     final MyFirstClass myFirstClass;
     MySecondClass(this.myFirstClass);
     }

    Khi đó, để tạo provider MySecondClass bạn sẽ phải viết code lồng nhau rất phức tạp. Tưởng tượng bạn có khoảng 10 class phụ thuộc nhau thì code sẽ như một mớ bùi nhùi 😟

    main.dart
    class MyWidget extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return Provider(
          create: (context) => MyFirstClass(),
          child: ProxyProvider<MyFirstClass, MySecondClass>(
            update: (context, firstClass, previous) => MySecondClass(firstClass),
            child: MyVisibleWidget(),
          ),
        );
      }
    }

    Thứ hai, Provider chỉ dựa vào “type” để tìm các đối tượng mà bạn cần. Nếu bạn có hai đối tượng cùng “type”, bạn chỉ có thể nhận được đối tượng gần nhất.

    main.dart

    class MyWidget extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return Provider(
          create: (context) => 'A String far away.',
          child: Provider(
            create: (context) => 'A String that is close.',
            builder: (context, child) {
              // Displays 'A String that is close.'
              // There's no way to obtain 'A String far away.'
              return Text(Provider.of<String>(context));
            },
          ),
        );
      }
    }

    Cuối cùng, nếu bạn cố gắng truy cập vào một “type” không được cung cấp, bạn sẽ chỉ gặp lỗi khi chạy. Bên trong bất kỳ widget nào, bạn có thể truy cập tới các Provider của mình theo type với cú pháp sau:

    Provider.of<MyType>(context)

    Nhưng nếu bạn không cẩn thận, có thể gặp lỗi với ProviderNotFoundException khi chạy chương trình, dù lúc biên dịch chương trình hoàn toàn không báo lỗi. Điều này không phải là lý tưởng vì chúng ta phải luôn cố gắng bắt càng nhiều lỗi càng tốt tại thời điểm compile-time.

    Hướng dẫn Riverpod trong Flutter (Flutter Riverpod Tutorial) 1

    Ưu điểm của Riverpod

    • Compile safe: Không còn gặp lỗi ProviderNotFoundException hoặc quên xử lý các trạng thái loading. Sử dụng Riverpod, nếu code được biên dịch thành công, nó sẽ hoạt động theo đúng ý bạn.
    • Provider, without its limitations: Riverpod có hỗ trợ multiple provider có cùng type; kết hợp các providers không đồng bộ; thêm providers từ mọi nơi, …
    • Không phụ thuộc vào Flutter: Create/share/tests providers, with no dependency on Flutter. Điều này bao gồm việc có thể listen providers mà không cần một BuildContext.

    2. Cách sử dụng Riverpod trong Flutter

    Hướng dẫn Riverpod trong Flutter (Flutter Riverpod Tutorial) 2

    Bước 1. Thêm thư viện riverpod

    Đầu tiên ta cần thêm package riverpod vào file pubspec.yaml trong dự án Flutter của bạn. Trong bài này, ta sẽ sử dụng flutter_riverpod, ngoài ra còn có hooks_riverpodriverpod.

    pubspec.yaml

    dependencies:
      flutter:
        sdk: flutter
      flutter_riverpod: ^0.12.1

    Bước 2. Khai báo biến toàn cục

    Riverpod’s Providers không được đặt trong widget tree. Thay vào đó, chúng là các biến toàn cục nằm ở bất kỳ file nào mà bạn muốn.

    final greetingProvider = Provider((ref) => 'Hello Riverpod!');

    Provider đơn giản nhất này có thể cung cấp một giá trị read-only. Có nhiều loại Providers khác nữa để làm việc với Futures, Streams, ChangeNotifier, StateNotifier,…

    Tham số ref có kiểu ProviderReference. Bạn sẽ thấy ở phần sau, nó chủ yếu được sử dụng để giải quyết sự phụ thuộc giữa các Provider.

    Mặc dù Provider object có thể truy cập toàn cục, nhưng điều này không có nghĩa là provided object (trong trường hợp này là chuỗi “Hello Riverpod!”) là global. Giống như với một hàm toàn cục, bạn có thể gọi nó từ bất cứ đâu nhưng giá trị trả về cũng có thể trở thành phạm vi cục bộ. Hãy xem xét đoạn code sau:

    function_analogy.dart
    String globalFunction() {
      return 'some value';
    }
    
    class MyClass {
      void _classMethod() {
        final valueLocalToThisMethod = globalFunction();
      }
    }

    Bước 3. ProviderScope

    Sau khi cài đặt xong Riverpod, chúng ta cần bao widget gốc của mình bằng ProviderScope.

    Gói Riverpod chỉ đi kèm với một InheritedWidget duy nhất cần được đặt phía trên toàn bộ widget trê được gọi là ProviderScope. Nó chịu trách nhiệm giữ một thứ gọi là ProviderContainer, thứ này có trách nhiệm lưu trữ trạng thái của các đối tượng Provider riêng lẻ.

    main.dart
    void main() {
      runApp(
        ProviderScope(
          child: MyApp(),
        ),
      );
    }

    Bước 4. Theo dõi một provider

    Làm cách nào để chúng ta lấy được string từ greetingProvider để có thể hiển thị trong Text? Thực tế có hai cách để làm điều đó.

    main.dart

    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Riverpod Tutorial',
          home: Scaffold(
            appBar: AppBar(
              title: Text('Riverpod Tutorial'),
            ),
            body: Center(
              child: Text('greeting goes here'),
            ),
          ),
        );
      }
    }

    Cách đầu tiên là thay đổi superclass tiện thành ConsumerWidget của package flutter_riverpod. Điều này thêm một tham số ScopedReader vào phương thức build của class đó. Widget sẽ được rebuild nếu có bất kỳ sự thay đổi nào xảy ra.

    main.dart

    class MyApp extends ConsumerWidget {
      @override
      Widget build(BuildContext context, ScopedReader watch) {
        // Gets the string from the provider and causes
        // the widget to rebuild when the value changes.
        final greeting = watch(greetingProvider);
    
        return MaterialApp(
          title: 'Riverpod Tutorial',
          home: Scaffold(
            appBar: AppBar(
              title: Text('Riverpod Tutorial'),
            ),
            body: Center(
              child: Text(greeting),
            ),
          ),
        );
      }
    }

    Cách khác để nhận được giá trị từ provider là dùng Consumer, cách này sẽ hữu ích nếu bạn muốn nhanh chóng tối ưu hóa việc xây dựng lại widget con của mình, không muốn các widget khác cũng phải rebuild lại theo. Trong trường hợp này ta chỉ cần xây dựng lại Text widget bản bị ảnh hưởng trên toàn bộ cây widget.

    main.dart

    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Riverpod Tutorial',
          home: Scaffold(
            appBar: AppBar(
              title: Text('Riverpod Tutorial'),
            ),
            body: Center(
              child: Consumer(
                builder: (context, ref, child) {
                  final greeting = ref.watch(greetingProvider);
                  return Text(greeting);
                },
              ),
            ),
          ),
        );
      }
    }
    

    Đọc một provider

    Đôi khi, không thể gọi “watch” vì bạn không ở trong phương thức build. Hoặc bạn chỉ muốn lấy giá trị từ provider ra chứ không muốn widget sẽ rebuild. Ví dụ: bạn có thể muốn thực hiện một hành động khi một nút được nhấn. Đó là khi bạn có thể gọi context.read(). Dưới đây là một loại provider khác – ChangeNotifierProvider:

    main.dart
    class IncrementNotifier extends ChangeNotifier {
      int _value = 0;
      int get value => _value;
    
      void increment() {
        _value += 1;
        notifyListeners();
      }
    }
    
    final incrementProvider = ChangeNotifierProvider((ref) => IncrementNotifier());

    Ta sẽ lấy ví dụ với Counter App. Text widget sẽ theo “watch” provider và tự động được rebuilt nếu xảy ra thay đổi và FloatingActionButton sẽ chỉ đọc provider để gọi phương thức increment() trên đó.

    main.dart

    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Riverpod Tutorial',
          home: Scaffold(
            body: Center(
              child: Consumer(
                builder: (context, watch, child) {
                  final incrementNotifier = watch(incrementProvider);
                  return Text(incrementNotifier.value.toString());
                },
              ),
            ),
            floatingActionButton: FloatingActionButton(
              onPressed: () {
                context.read(incrementProvider).increment();
              },
              child: Icon(Icons.add),
            ),
          ),
        );
      }
    }

    3. Những điểm tuyệt vời của Riverpod

    Sử dụng nhiều provider cùng type

    Riverpod’s providers objects không dựa vào types để tìm kiếm các provider, nên có nhiều provider cùng type mà không gặp vấn đề gì
    example.dart
    final firstStringProvider = Provider((ref) => 'First');
    final secondStringProvider = Provider((ref) => 'Second');
    
    // Somewhere inside a ConsumerWidget
    final first = watch(firstStringProvider);
    final second = watch(secondStringProvider);

    Dependency between providers

    Bất kỳ ứng dụng nào trong thực tế đều có sự phụ thuộc giữa các lớp. Ví dụ: bạn có thể có ChangeNotifier phụ thuộc vào Repository,mà nó lại phụ thuộc vào HttpClient. Xử lý các phụ thuộc như vậy với Riverpod rất đơn giản và dễ đọc.

    Với ví dụ đơn giản sau, chỉ có một FutureProvider phụ thuộc trực tiếp vào một FakeHttpClient. Việc getting một provider khác bên trong function của provider được thực hiện bằng cách gọi read trên tham số ProviderReference – ref luôn được chuyển vào. Nếu bạn phụ thuộc vào provider có giá trị có thể thay đổi, bạn cũng có thể gọi watch.

    main.dart

    class FakeHttpClient {
      Future<String> get(String url) async {
        await Future.delayed(const Duration(seconds: 1));
        return 'Response from $url';
      }
    }
    
    final fakeHttpClientProvider = Provider((ref) => FakeHttpClient());
    final responseProvider = FutureProvider<String>((ref) async {
      final httpClient = ref.read(fakeHttpClientProvider);
      return httpClient.get('https://resocoder.com');
    });

    Sử dụng các giá trị từ FutureProvider từ UI thay cho FutureBuilders rất tuyệt vời. Riverpod giúp việc xây dựng các widgets dựa trên Future một cách dễ dàng.

    main.dart

    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Riverpod Tutorial',
          home: Scaffold(
            body: Center(
              child: Consumer(
                builder: (context, watch, child) {
                  final responseAsyncValue = watch(responseProvider);
                  return responseAsyncValue.map(
                    data: (_) => Text(_.value),
                    loading: (_) => CircularProgressIndicator(),
                    error: (_) => Text(
                      _.error.toString(),
                      style: TextStyle(color: Colors.red),
                    ),
                  );
                },
              ),
            ),
          ),
        );
      }
    }

    Passing arguments to providers

    Nếu bạn muốn chuyển một URL do người dùng xác định đến responseProvider? Hãy dùng family, thay đổi responseProvider thành như sau…

    main.dart

    final responseProvider =
        FutureProvider.family<String, String>((ref, url) async {
      final httpClient = ref.read(fakeHttpClientProvider);
      return httpClient.get(url);
    });

    Bạn có thể thử thay đổi chuỗi URL được mã hóa cứng và bạn sẽ thấy rằng hàm này sẽ FutureProvider chạy lại hàm tạo của nó mỗi khi bạn thay đổi chuỗi được truyền vào.

    main.dart

    final responseAsyncValue = watch(responseProvider('https://resocoder.com'));

    Automatically disposing of state

    Bộ nhớ đệm cho provider’s state là rất tuyệt nhưng đôi khi bạn muốn hủy trạng thái của một provider khi nó không còn được sử dụng nữa vì nhiều lý do như:

    • Khi sử dụng Firebase, bạn muốn đóng connect để tránh các phí phát sinh
    • Để thiết lập lại trạng thái khi người dùng rời khỏi màn hình và vào lại.
    main.dart
    final responseProvider =
        FutureProvider.autoDispose.family<String, String>((ref, url) async {
      final httpClient = ref.read(fakeHttpClientProvider);
      return httpClient.get(url);
    });

    autoDispose sẽ loại bỏ provider’s state ngay khi provider không được sử dụng. Trong ví dụ trên, điều này xảy ra ta thay đổi đối số được truyền vào provider family. Tuy nhiên, autoDispose hữu ích ngay cả khi bạn không sử dụng family modifier. Trong trường hợp đó, việc xóa bỏ được bắt đầu khi ConsumerWidget một provider bị disposed.

    Bài viết được biên tập từ https://resocoder.com/2020/11/27/flutter-riverpod-tutorial-the-better-provider/

  • Các câu hỏi phỏng vấn Flutter

    Các câu hỏi phỏng vấn Flutter

    Các câu hỏi phỏng vấn Flutter

    Flutter ngày càng được nhiều người quan tâm nhờ khả năng phát triển app đa nền tảng. Dưới đây, chúng tôi giới thiệu Các câu hỏi phỏng vấn Flutter để bạn đọc tham khảo. Bạn có thể xem thêm KINH NGHIỆM PHỎNG VẤN FLUTTER.

    Flutter là gì?

    Flutter là một bộ công cụ giao diện người dùng để tạo các ứng dụng di động nhanh, đẹp, được biên dịch nguyên bản với một ngôn ngữ lập trình và một cơ sở code duy nhất. Nó là một framework phát triển code nguồn mở được phát triển bởi Google. Nói chung, Flutter không phải là một ngôn ngữ; nó là một SDK. Ứng dụng Flutter sử dụng ngôn ngữ lập trình Dart để tạo ứng dụng. Phiên bản alpha đầu tiên của Flutter được phát hành vào tháng 5 năm 2017.

    Flutter chủ yếu được tối ưu hóa cho các ứng dụng di động 2D có thể chạy trên cả nền tảng Android và iOS. Chúng tôi cũng có thể sử dụng nó để tạo các ứng dụng đầy đủ tính năng, bao gồm máy ảnh, bộ nhớ, vị trí địa lý, mạng, SDK của bên thứ ba, v.v.

    Mời bạn xem giới thiệu chi tiết hơn tại bài Flutter là gì?

    Dart là gì?

    Dart là một ngôn ngữ lập trình hướng đối tượng, có mục đích chung với cú pháp kiểu C. Nó là code nguồn mở và được phát triển bởi Google vào năm 2011. Mục đích của lập trình Dart là tạo giao diện người dùng frontend cho web và ứng dụng di động. Nó là một ngôn ngữ quan trọng để tạo ứng dụng Flutter. Ngôn ngữ Dart có thể được biên dịch cả AOT (Ahead-of-Time) và JIT (Just-in-Time.

    Học Flutter có cần học Dart không?

    Có, việc học ngôn ngữ Dart để xây dựng ứng dụng Flutter là rất cần thiết. Vì Flutter chỉ là một bộ khung (framework) sử dụng ngôn ngữ Dart để tạo nên ứng dụng.

    Flutter có miễn phí không?

    Có. Flutter hoàn toàn miễn phí và mã nguồn mở.

    Widget trong Flutter là gì?

    Một ứng dụng Flutter luôn được coi là một cây các material. Bất cứ khi nào bạn định viết code để xây dựng bất cứ thứ gì trong Flutter, nó sẽ nằm bên trong một widget. Các widget mô tả chế độ xem ứng dụng của bạn trông như thế nào với cấu hình và trạng thái hiện tại của chúng. Khi bạn thực hiện bất kỳ thay đổi nào trong code, widget con sẽ xây dựng lại mô tả của nó bằng cách tính toán sự khác biệt của widget con hiện tại và trước đó để xác định những thay đổi tối thiểu đối với việc hiển thị trong giao diện người dùng của ứng dụng.

    Các widget được lồng vào nhau để xây dựng ứng dụng. Nó có nghĩa là thư mục gốc của ứng dụng của bạn tự nó là một widget và tất cả các cách nhìn xuống cũng là một widget. Ví dụ: một widget có thể hiển thị một cái gì đó, có thể xác định thiết kế, có thể xử lý tương tác, v.v.

    Sự khác nhau giữa Stateful Widget và Stateless Widget?

    Một widget Stateful có thông tin state. Nó được gọi là động vì nó có thể thay đổi dữ liệu bên trong trong suốt thời gian tồn tại của widget. Một widget cho phép chúng ta làm mới màn hình được gọi là Stateful widget. widget con này không có phương thức build(). Nó có phương thức createState(), trả về một lớp mở rộng Lớp state Flutters. Các ví dụ về widget Stateful là Checkbox, Radio, Slider, InkWell, Form và TextField.

    widget không trạng thái(Stateless) không có bất kỳ thông tin trạng thái nào. Nó vẫn tĩnh trong suốt vòng đời của nó. Ví dụ về widget không trạng thái là Văn bản, Hàng, Cột, Vùng chứa, v.v. Nếu màn hình hoặc widget chứa nội dung tĩnh, nó phải là widget Stateless, nhưng nếu bạn muốn thay đổi nội dung, nó cần phải là widget Stateful.

    Các trình soạn thảo tốt nhất để phát triển Flutter là gì?

    Các công cụ phát triển Flutter cho phép phát triển Flutter nhanh hơn và do đó thúc đẩy quy trình làm việc của nhà phát triển. Flutter IDE và các công cụ cần một số plugin để phát triển các ứng dụng di động. Các plugin giúp chúng tôi biên dịch, phân tích code và phát triển Flutter. IDE phổ biến cho sự phát triển của Flutter như sau:

    • Android Studio
    • Visual Studio
    • IntelliJ IDEA
    • Xcode

    Tệp pubspec.yaml là gì?

    Đó là tệp cấu hình của dự án sẽ sử dụng rất nhiều trong quá trình làm việc với dự án Flutter. Nó cho phép bạn cách ứng dụng của bạn hoạt động. Nó cũng cho phép chúng tôi thiết lập các ràng buộc cho ứng dụng. Tệp này chứa:

    • Cài đặt chung của dự án như tên, mô tả và phiên bản của dự án.
    • Sự phụ thuộc của dự án.
    • Nội dung dự án (ví dụ: hình ảnh, âm thanh, v.v.).

    Các gói và plugin trong Flutter là gì?

    Gói là một nhóm các loại lớp, giao diện và gói con tương tự nhau. Các gói và plugin giúp chúng tôi xây dựng ứng dụng mà không cần phải phát triển mọi thứ từ các gói. Trong Flutter, nó cho phép bạn nhập các widget hoặc chức năng mới vào ứng dụng. Các gói và plugin có một sự khác biệt rất nhỏ. Nói chung, các gói là các thành phần mới hoặc code được viết bằng ngôn ngữ Dart, trong khi các plugin cho phép nhiều chức năng hơn trên thiết bị bằng cách sử dụng code gốc. Trong DartPub, cả gói và plugin đều được gọi là gói.

    Ưu điểm của Flutter là gì?

    Các câu hỏi phỏng vấn Flutter 3

    Các ưu điểm phổ biến của Flutter framework như sau:

    • Phát triển đa nền tảng: Tính năng này cho phép Flutter viết code một lần, duy trì và có thể chạy trên các nền tảng khác nhau. Nó tiết kiệm thời gian, công sức và tiền bạc của các nhà phát triển.
    • Phát triển nhanh hơn: Hiệu suất của ứng dụng Flutter rất nhanh. Flutter biên dịch ứng dụng bằng cách sử dụng thư viện nhánh C / C ++ giúp ứng dụng gần với code máy hơn và mang lại cho ứng dụng hiệu suất gốc tốt hơn.
    • Cộng đồng tốt: Flutter có hỗ trợ cộng đồng tốt, nơi các nhà phát triển có thể hỏi các vấn đề và nhận được kết quả nhanh chóng.
    • Tải lại trực tiếp và nóng: Nó làm cho quá trình phát triển ứng dụng cực kỳ nhanh chóng. Tính năng này cho phép chúng tôi thay đổi hoặc cập nhật code được phản ánh ngay sau khi các thay đổi được thực hiện.
    • code tối thiểu: Ứng dụng Flutter được phát triển bởi ngôn ngữ lập trình Dart, sử dụng biên dịch JIT và AOT để cải thiện thời gian khởi động tổng thể, hoạt động và tăng tốc hiệu suất. JIT nâng cao hệ thống phát triển và làm mới giao diện người dùng mà không cần nỗ lực thêm vào việc xây dựng hệ thống mới.
    • Tập trung vào giao diện người dùng: Nó có giao diện người dùng tuyệt vời vì nó sử dụng widget tập trung vào thiết kế, các công cụ phát triển cao, API nâng cao và nhiều tính năng khác.
    • Tài liệu: Flutter có hỗ trợ tài liệu rất tốt. Nó được tổ chức và nhiều thông tin hơn. Chúng ta có thể lấy mọi thứ mà chúng ta muốn viết ở một nơi.

    Bạn có thể cài đặt Flutter bằng cách nào?

    Để cài đặt và chạy Flutter trên hệ thống Windows, MacOS trước tiên bạn cần đáp ứng các yêu cầu này đối với môi trường phát triển của mình.

    Hệ điều hành Windows 7 trở lên (Tôi là Windows 10. Bạn cũng có thể sử dụng Mac hoặc Linux OS.).
    Dung lượng đĩa 400 MB (Nó không bao gồm không gian đĩa cho IDE / công cụ).
    Công cụ 1. Windows PowerShell2. Git dành cho Windows 2.x (Tại đây, Sử dụng Git từ tùy chọn Dấu nhắc Lệnh của Windows).
    SDK Flutter SDK dành cho Windows
    IDE Android Studio (Chính thức)

    Mời bạn tham khảo thêm Cài đặt Flutter với Visual Studio Code

    So sánh Flutter và React Native?

    • Flutter và React Native đều được sử dụng để phát triển ứng dụng kết hợp gốc từ một cơ sở code duy nhất. Các ứng dụng này có thể chạy trên nền tảng iOS và Android.
    • React Native do Facebook phát triển, trong khi framework công tác Flutter lần đầu tiên được giới thiệu bởi Google. Vì vậy, cả hai framework đều có tính năng và tính cộng đồng rất tốt.
    • Flutter sử dụng ngôn ngữ Dart để tạo ứng dụng, trong khi React Native sử dụng JavaScript để xây dựng ứng dụng.
    • Theo quan điểm của nhà phát triển, rất khó để lựa chọn trong số chúng. Do đó, rất khó để chọn ra người chiến thắng giữa Flutter và React Native.

    Tại sao build app Flutter lần đầu tiên mất nhiều thời gian?

    Khi bạn dựng ứng dụng Flutter lần đầu tiên, sẽ mất nhiều thời gian hơn. Đó là do Flutter đã xây dựng tệp APK hoặc IPA dành riêng cho thiết bị. Do đó, Gradle và Xcode được sử dụng để xây dựng tệp, mất nhiều thời gian.

    Tại sao thư mục Android và iOS lại nằm trong dự án Flutter?

    • Android: Thư mục này chứa một dự án Android hoàn chỉnh. Nó được sử dụng khi bạn tạo ứng dụng Flutter cho Android. Khi code Flutter được biên dịch thành code gốc, nó sẽ được đưa vào dự án Android này, do đó kết quả là một ứng dụng Android gốc. Ví dụ : Khi bạn đang sử dụng trình giả lập Android, dự án Android này được sử dụng để xây dựng ứng dụng Android, được triển khai thêm cho Thiết bị ảo Android.
    • iOS: Thư mục này chứa một dự án Mac hoàn chỉnh. Nó được sử dụng khi bạn xây dựng ứng dụng Flutter cho iOS. Nó tương tự như thư mục Android, được sử dụng khi phát triển ứng dụng cho Android. Khi code Flutter được biên dịch thành code gốc, nó sẽ được đưa vào dự án iOS này, để kết quả là một ứng dụng iOS gốc. Chỉ có thể xây dựng ứng dụng Flutter cho iOS khi bạn đang làm việc trên macOS và Xcode IDE.

    Tween Animation là gì?

    Đây là hình thức rút gọn của in-betweening. Trong hoạt ảnh tween, bắt buộc phải xác định điểm đầu và điểm cuối của hoạt ảnh. Nó có nghĩa là hoạt ảnh bắt đầu với giá trị bắt đầu, sau đó đi qua một loạt các giá trị trung gian và cuối cùng đạt đến giá trị kết thúc. Nó cũng cung cấp dòng thời gian và đường cong, xác định thời gian và tốc độ của quá trình chuyển đổi. framework công cụ cung cấp tính toán về cách chuyển đổi từ điểm đầu và điểm cuối.

    Giải thích Hot Reload trong Flutter?

    Tính năng tải lại nóng cho phép bạn nhanh chóng và dễ dàng thực hiện một thử nghiệm trong dự án. Nó giúp xây dựng giao diện người dùng, thêm các tính năng mới, sửa lỗi và phát triển ứng dụng nhanh chóng. Để thực hiện tải lại nóng ứng dụng Flutter, hãy làm theo các bước sau:

    Chạy ứng dụng trong trình chỉnh sửa Flutter hoặc cửa sổ dòng lệnh được hỗ trợ.

    Sửa đổi bất kỳ tệp Dart nào trong dự án.

    Nếu bạn sử dụng IDE hỗ trợ Flutter, hãy chọn Lưu tất cả hoặc nhấp vào nút Tải lại nóng trên thanh công cụ. Ngay lập tức, bạn có thể xem kết quả trong trình mô phỏng hoặc thiết bị thực của mình.

    Kể tên một số ứng dụng phổ biến sử dụng Flutter?

    Ngày nay, nhiều tổ chức sử dụng Flutter để xây dựng ứng dụng. Một số ứng dụng phổ biến nhất được xây dựng trên Flutter như sau:

    • Google Ads
    • Reflectly
    • Alibaba
    • Birch Finance
    • Coach Yourself
    • Tencent
    • Watermaniac

    Kể tên gói cơ sở dữ liệu phổ biến được sử dụng trong Flutter?

    Các gói cơ sở dữ liệu phổ biến và được sử dụng nhiều nhất được sử dụng trong Flutter như sau:

    • Cơ sở dữ liệu sqflite: Nó cho phép truy cập và thao tác với cơ sở dữ liệu SQLite.
    • Cơ sở dữ liệu Firebase: Nó sẽ cho phép bạn truy cập và thao tác với cơ sở dữ liệu đám mây.

    Animation nào cho phép bạn thể hiện hành vi trong thế giới thực?

    Animation dựa trên Vật lý cho phép bạn thể hiện hành vi trong thế giới thực trong Flutter.

    Sự khác biệt giữa Khởi động lại Nóng và Tải lại Nóng là gì?

    Sau đây là những điểm khác biệt cơ bản giữa Khởi động lại nóng và Tải lại nóng:

    Tải lại nóng (Hot reload) Khởi động lại nóng
    Nó hoạt động với một phím r nhỏ trên thiết bị đầu cuối hoặc dấu nhắc lệnh. Nó chủ yếu hoạt động bằng tay
    Tính năng tải lại nóng cho phép chúng tôi nhanh chóng biên dịch mã mới được thêm vào tệp và gửi chúng đến Máy ảo Dart (DVM). Sau khi hoàn tất cập nhật DVM, nó sẽ cập nhật ngay giao diện người dùng của ứng dụng. Nó cho phép các nhà phát triển có được một ứng dụng được biên dịch đầy đủ vì nó phá hủy các giá trị Trạng thái đã có và đặt chúng thành mặc định. Trên mỗi lần Khởi động lại nóng, cây widget ứng dụng của chúng ta được xây dựng lại hoàn toàn với code đã nhập mới.
    Nó giúp xây dựng giao diện người dùng, thêm các tính năng mới, sửa lỗi và phát triển ứng dụng nhanh chóng. Mất nhiều thời gian hơn Tải lại nóng để biên dịch và cập nhật ứng dụng.

    22. Trong đoạn mã dưới đây, hãy chuyển makeMangoShake() thành getter có tên là mangoshake bằng cách sử dụng cú pháp viết tắt “fat arrow”: 

    class Recipe {  
      int mango;  
      int milk;  
      int sugar;  
      Recipe(this.mango, this.milk, this.sugar);   
      int makeMangoShake() {  
        return mango+milk+sugar;  
      }  
    }

    Fat Arrow (=>) được sử dụng khi phương thức chứa một dòng code. Chúng ta có thể sử dụng nó bằng cú pháp sau:

    methodName(parameters) => statement;

    Cần lưu ý rằng chúng ta không thể sử dụng từ khóa return có mũi tên béo (=>). Sau khi chuyển makeMangoShake() thành một mũi tên, nó sẽ giống như đoạn mã dưới đây:

    int get mangoshake => mango + milk + sugar;

    Sự khác biệt giữa các hàm “main()” và “runApp()” trong Flutter là gì?

    Chúng ta có thể phân biệt các hàm chính và hàm runApp trong Flutter như sau:

    • Hàm main() chịu trách nhiệm khởi động chương trình. Nếu không có hàm main(), chúng ta không thể viết bất kỳ chương trình nào trên Flutter.
    • Hàm runApp() có nhiệm vụ trả về các widget được gắn vào màn hình dưới dạng gốc của cây widget và sẽ được hiển thị trên màn hình.

    Khi nào bạn nên sử dụng mainAxisAlignment và crossAxisAlignment?

    Chúng ta có thể sử dụng crossAxisAlignment và mainAxisAlignment để kiểm soát cách các widget hàng và cột sắp xếp các con của nó dựa trên sự lựa chọn của chúng ta.

    Trục chéo của hàng sẽ chạy theo chiều dọc và trục chính sẽ chạy theo chiều ngang. Xem hình ảnh minh họa bên dưới để hiểu rõ hơn.

    Các câu hỏi phỏng vấn Flutter 4

    Trục chéo của cột sẽ chạy theo chiều ngang và trục chính sẽ chạy theo chiều dọc. Hình ảnh minh họa dưới đây giải thích rõ ràng hơn.

    Các câu hỏi phỏng vấn Flutter 5

    Sự khác biệt giữa SizedBox và Container là gì?

    • Container trong Flutter là một widget có thể chứa nhiều widget và quản lý chúng một cách hiệu quả thông qua chiều rộng, chiều cao, phần đệm, màu nền, v.v. Nếu chúng ta có một widget cần một số kiểu nền có thể là hạn chế về màu sắc, hình dạng hoặc kích thước , chúng tôi có thể bọc nó trong một widget vùng chứa.
    • SizedBox trong Flutter là một hộp đi kèm với kích thước được chỉ định. Không giống như Container, nó không cho phép chúng ta thiết lập màu sắc hoặc trang trí cho widget. Chúng tôi chỉ có thể sử dụng nó để xác định kích thước của tiện ích được truyền khi còn nhỏ. Nó có nghĩa là nó buộc widget con của nó phải có chiều rộng hoặc chiều cao cụ thể.

    Stream trong Flutter là gì?

    Luồng là một chuỗi các sự kiện không đồng bộ. Nó cung cấp một chuỗi dữ liệu không đồng bộ. Nó cũng giống như một đường ống mà chúng ta đặt một số giá trị vào một đầu và nếu chúng ta có một người nghe ở đầu kia, nó sẽ nhận được giá trị đó. Chúng tôi có thể giữ nhiều người nghe trong một luồng và tất cả những người nghe đó sẽ nhận được cùng một giá trị khi được đưa vào đường dẫn.

    Chúng tôi có thể xử lý luồng bằng cách sử dụng hàm chờ hoặc nghe từ API luồng. Nó có một cách để phản hồi các lỗi. Chúng ta có thể tạo luồng theo nhiều cách, nhưng chúng có thể được sử dụng theo cách giống nhau. Xem ví dụ dưới đây:

    Future<int> sumStream(Stream<int> stream) async {  
        var sum = 0;  
        await for (var value in stream) {  
          sum = sum + value;  
        }  
        return sum;  
      }

    Các loại Stream trong Flutter?

    Stream có thể có hai loại, đó là:

    • Single subscription streams (Các luồng đăng ký đơn lẻ) Đây là loại luồng phổ biến nhất chứa một chuỗi các sự kiện, là các phần của một tổng thể lớn hơn. Nó sẽ cung cấp các sự kiện theo đúng thứ tự và không bỏ sót bất kỳ sự kiện nào. Nếu thiếu bất kỳ sự kiện nào, thì phần còn lại của luồng sẽ không có ý nghĩa gì. Luồng này chủ yếu được sử dụng để đọc tệp hoặc nhận yêu cầu web. Nó sẽ nghe một lần, và nếu nó đang nghe lại, điều đó có nghĩa là đã bỏ lỡ một sự kiện ban đầu. Khi nó bắt đầu nghe, dữ liệu sẽ được tìm nạp và cung cấp theo từng phần.
    • Broadcast streams (Các luồng phát sóng) Đây là một loại luồng được sử dụng cho các thư riêng lẻ có thể được xử lý từng thư một mà không cần biết về các sự kiện trước đó. Nó có thể có nhiều người nghe để nghe đồng thời và chúng ta có thể nghe lại sau khi hủy đăng ký trước đó. Sự kiện chuột này trong trình duyệt là một loại luồng này.

    Tại sao phương thức build() trên State mà không phải StatefulWidgets?

    Lý do chính đằng sau điều này là StatefulWidget sử dụng một lớp State riêng biệt mà không xây dựng một phương thức bên trong phần thân của nó. Nó có nghĩa là tất cả các trường bên trong Widget là bất biến và bao gồm tất cả các lớp con của nó.

    Mặt khác, StatelessWidget có các phương thức xây dựng và liên kết bên trong cơ thể của nó. Đó là do bản chất của StatelessWidget, được hiển thị hoàn toàn trên màn hình bằng cách sử dụng thông tin được cung cấp. Nó cũng không cho phép bất kỳ thay đổi nào trong tương lai đối với thông tin State của nó.

    StatefulWidget cho phép chúng tôi thay đổi thông tin State trong quá trình sử dụng ứng dụng. Do đó, nó không phù hợp để lưu trữ trong một phương thức xây dựng để thỏa mãn các điều kiện lớp Widget nơi tất cả các trường là bất biến. Đây là lý do chính để giới thiệu State . Ở đây, chúng ta chỉ cần ghi đè hàm createState () để đính kèm Trạng thái đã xác định với StatefulWidget, và sau đó tất cả các thay đổi dự kiến ​​sẽ xảy ra trong một lớp riêng biệt.

    Các chế độ build khác nhau trong Flutter là gì?

    Công cụ Flutter hỗ trợ ba chế độ trong khi biên dịch ứng dụng. Các chế độ biên dịch này có thể được chọn tùy thuộc vào vị trí của chúng ta trong chu trình phát triển. Tên của các chế độ là:

    • Debug
    • Profile
    • Release

    Tại sao chúng ta cần mixin?

    Dart không hỗ trợ nhiều thừa kế. Vì vậy, để triển khai nhiều kế thừa trong Flutter / Dart, chúng ta cần các mixin. Mixins cung cấp một cách để viết code của lớp có thể sử dụng lại trong nhiều phân cấp lớp.

    Tại sao chúng ta sử dụngTicker trong Flutter?

    Ticker trong Flutter là tốc độ làm mới hình ảnh động của chúng ta. Nó là một lớp gửi tín hiệu ở một khoảng thời gian đều đặn, tức là khoảng 60 lần mỗi giây. Chúng ta có thể hiểu điều đó bằng đồng hồ của mình, đồng hồ này hoạt động đều đặn. Tại mỗi lần đánh dấu, Ticker cung cấp một phương thức gọi lại với khoảng thời gian kể từ lần đánh dấu đầu tiên vào mỗi giây, sau khi nó được bắt đầu. Ngay cả khi các code bắt đầu vào các thời điểm khác nhau, nó luôn được đồng bộ hóa tự động.

    Key trong Flutter là gì?

    • Các Key trong Flutter được sử dụng làm code định danh cho Widget, Elements và SemanticsNodes. Chúng ta có thể sử dụng nó khi một widget mới cố gắng cập nhật một phần tử hiện có; sau đó, khóa của nó phải giống với khóa widget hiện tại được liên kết với phần tử.
    • Các khóa không được khác nhau giữa các Phần tử trong cùng một gốc.
    • Các lớp con của Key phải là GlobalKey hoặc LocalKey.
    • Key rất hữu ích khi chúng ta cố gắng thao tác (chẳng hạn như thêm, xóa hoặc sắp xếp lại thứ tự) một tập hợp các widget cùng loại có trạng thái nào đó.

    Làm thế nào bạn sẽ thực thi code chỉ trong chế độ gỡ lỗi?

    Để thực thi code chỉ trong chế độ gỡ lỗi, trước tiên chúng ta cần nhập nền tảng phi tiêu như bên dưới:

    import 'package:flutter/foundation.dart' as Foundation;

    Tiếp theo, chúng ta cần sử dụng kReleaseMode như bên dưới:

    if (Foundation.kReleaseMode){ // is Release Mode ??
    print('release mode');
    } else {
    print('debug mode');
    }

    Chế độ profile là gì, và bạn sử dụng nó khi nào?

    Chế độ hồ sơ(Profile) được sử dụng để đo hiệu suất của các ứng dụng của chúng ta. Trong chế độ này, một số khả năng gỡ lỗi được duy trì để xác định hiệu suất ứng dụng của bạn. Chế độ này bị tắt trên trình giả lập và trình mô phỏng vì chúng không đại diện cho hiệu suất thực.

    Chúng ta có thể sử dụng lệnh dưới đây để biên dịch chế độ cấu hình:

    Chế độ release là gì và bạn sử dụng nó khi nào?

    • Chế độ phát hành (release) cho phép chúng ta tối ưu hóa code và tạo chúng mà không có bất kỳ dữ liệu gỡ lỗi nào ở dạng được tối ưu hóa hoàn toàn. Trong chế độ này, nhiều code của ứng dụng sẽ bị xóa hoặc viết lại hoàn toàn.
    • Chúng ta sử dụng chế độ này khi chúng ta sẵn sàng phát hành ứng dụng. Nó cho phép tối ưu hóa tối đa và kích thước dấu chân tối thiểu của ứng dụng.
    • Chúng ta có thể sử dụng lệnh dưới đây để biên dịch chế độ phát hành:

    flutter run --release

    Sự khác biệt giữa WidgetsApp và MaterialApp là gì?

    Biểu đồ so sánh dưới đây giải thích sự khác biệt cơ bản giữa WidgesApp và MaterialApp:

    WidgetsApp MaterialApp
    WidgetsApp được sử dụng để điều hướng cơ bản. Nó bao gồm nhiều widget nền tảng cùng với thư viện widget mà Flutter sử dụng để tạo giao diện người dùng của ứng dụng của chúng ta. MaterialApp, cùng với thư viện material, là một lớp được xây dựng trên đầu WidgetsApp và thư viện của nó. Nó triển khai thiết kế Material Design cung cấp giao diện thống nhất cho ứng dụng của chúng ta trên bất kỳ nền tảng nào.
    Lớp WidgetsApp là lớp cơ sở cho lớp MaterialApp. Nó cung cấp nhiều công cụ thú vị như Bộ điều hướng hoặc Chủ đề để phát triển ứng dụng.
    Nó bao bọc một số widget cần thiết để xây dựng ứng dụng. Nó bao gồm một số widget cần thiết cho các ứng dụng thiết kế vật liệu xây dựng.

    BuildContext là gì?

    BuildContext trong Flutter là một phần của các widget trong cây Element để mỗi widget có BuildContext của riêng mình. Chúng ta chủ yếu sử dụng nó để tham chiếu đến một widget hoặc chủ đề khác. Ví dụ, nếu chúng ta muốn sử dụng một yếu tố thiết kế material design, thì nó bắt buộc phải tham chiếu nó đến Scaffold. Chúng ta có thể lấy nó bằng phương thức Scaffold.of (context).

    Bạn có thể thực hiện những loại kiểm tra nào trong Flutter?

    Kiểm tra là một hoạt động được sử dụng để xác minh và xác thực ứng dụng, không có lỗi và đáp ứng các yêu cầu của người dùng. Nói chung, chúng ta có thể sử dụng ba loại kiểm tra này trong Flutter:

    • Unit Tests: Nó kiểm tra một chức năng, phương thức hoặc lớp. Mục tiêu của nó là đảm bảo tính đúng đắn của code trong nhiều điều kiện khác nhau. Thử nghiệm này được sử dụng để kiểm tra tính hợp lệ của logic kinh doanh của chúng ta.
    • Widget Tests: Nó kiểm tra một widget duy nhất. Mục tiêu của nó là đảm bảo rằng giao diện người dùng của widget trông và tương tác với các widget khác như mong đợi.
    • Integration Tests: Nó xác thực một ứng dụng hoàn chỉnh hoặc một phần lớn của ứng dụng. Mục tiêu của nó là đảm bảo rằng tất cả các widget và dịch vụ cùng hoạt động như mong đợi.

    Toán tử kiểm tra Null là gì?

    Dart cung cấp một số thông tin hữu ích để xử lý các giá trị null.

    1. Toán tử gán “?? =” chỉ gán giá trị cho một biến khi biến đó đang rỗng (null).

    int a; // Initial value of a is null.  
    a ??= 5;  
    print(a); // It will print 5.

    2. Toán tử “??” được sử dụng để đánh giá và trả về giá trị giữa hai biểu thức. Đầu tiên, nó thực thi và kiểm tra biểu thức bên trái nếu khác rỗng thì trả về giá trị của biểu thức đó; nếu không, nó sẽ thực thi và trả về giá trị của biểu thức bên phải:

    print(3 ?? 5); // It will print 3.  
    print(null ?? 5); // It will print 5.

    Sự khác nhau giữa toán tử “??” và “?”

    Toán tử ??  Toán tử ? 
    Các “??” toán tử được sử dụng để đánh giá và trả về giá trị giữa hai biểu thức.

    Nó có thể được sử dụng như sau:expr1 ?? expr2Toán tử này đầu tiên kiểm tra biểu thức 1 và nếu nó không phải là null, trả về giá trị của nó; nếu không, nó sẽ đánh giá và trả về giá trị của biểu thức 2.

    Các “?” toán tử được sử dụng để đánh giá và trả về giá trị giữa hai biểu thức dựa trên điều kiện đã cho.

    Nó có thể được sử dụng như sau:điều kiện? expr1: expr2Toán tử này đầu tiên kiểm tra điều kiện và nếu nó đúng, nó sẽ đánh giá expr1 và trả về giá trị của nó (nếu điều kiện được khớp). Nếu không, nó sẽ đánh giá và trả về giá trị của expr2.

  • Flutter là gì?

    Flutter là gì?

    Flutter là gì?

    Để trả lời câu hỏi Flutter là gì, những đặc điểm cơ bản của Flutter, chúng tôi xin được trích đăng một phần đồ án tốt nghiệp của bạn Đỗ Thế Hiệp, sinh viên trường ĐH QUẢN LÝ và CÔNG NGHỆ HẢI PHÒNG.

    Flutter là gì?

    Flutter là một bộ SDK đa nền tảng có thể hoạt động trên iOS và Android do Google phát triển được sử dụng để tạo ra các ứng dụng dành cho di động (native app).

    Flutter gồm 2 thành phần quan trọng:

    • Một SDK (Software Development Kit): Một bộ sưu tập các công cụ sẽ giúp bạn phát triển các ứng dụng của mình.
    • Một Framework (UI Library based on widgets): Một tập hợp các thành phần giao diện người dùng (UI) có thể tái sử dụng (button, text inputs, slider, v.v.) giúp bạn có thể cá nhân hóa tùy theo nhu cầu của riêng mình.

    Nói chung, tạo một ứng dụng di động là một công việc rất phức tạp và đầy thử thách. Có rất nhiều framework có sẵn, cung cấp các tính năng tuyệt vời để phát triển các ứng dụng di động. Để phát triển các ứng dụng dành cho thiết bị di động, Android cung cấp một framework gốc dựa trên ngôn ngữ Java và Kotlin, trong khi iOS cung cấp một framework dựa trên ngôn ngữ Objective-C/Swift.

    Vì vậy, chúng ta cần hai ngôn ngữ và framework khác nhau để phát triển ứng dụng cho cả hai hệ điều hành. Ngày nay, để khắc phục sự phức tạp này, có một số framework đã được giới thiệu hỗ trợ cả hệ điều hành cùng với các ứng dụng dành cho máy tính để bàn. Những loại framework này được gọi là công cụ phát triển đa nền tảng [1] .

    Framework phát triển đa nền tảng có khả năng viết một code và có thể triển khai trên nhiều nền tảng khác nhau (Android, iOS và Máy tính để bàn). Nó tiết kiệm rất nhiều thời gian và nỗ lực phát triển của các nhà phát triển.

    Có một số công cụ có sẵn để phát triển đa nền tảng, bao gồm các công cụ dựa trên web. Mỗi framework này có mức độ thành công khác nhau trong ngành công nghiệp di động. Gần đây, một framework công tác mới đã được giới thiệu trong họ phát triển đa nền tảng có tên là Flutter được phát triển từ Google.

    Flutter là một bộ công cụ giao diện người dùng để tạo các ứng dụng nhanh, đẹp, được biên dịch nguyên bản cho thiết bị di động, web và máy tính để bàn với một ngôn ngữ lập trình và cơ sở code duy nhất. Nó là miễn phí và code nguồn mở. Ban đầu nó được phát triển từ Google và bây giờ được quản lý theo tiêu chuẩn ECMA. Ứng dụng Flutter sử dụng ngôn ngữ lập trình Dart để tạo ứng dụng.

    Flutter chủ yếu được tối ưu hóa cho các ứng dụng di động 2D có thể chạy trên cả nền tảng Android và iOS. Chúng ta cũng có thể sử dụng nó để xây dựng các ứng dụng đầy đủ tính năng, bao gồm máy ảnh, bộ nhớ, vị trí địa lý, mạng, SDK của bên thứ ba, v.v.

    Điều làm Flutter trở lên khác biệt?

    Flutter khác với các framework khác vì nó không sử dụng WebView cũng như các widget OEM (Original Equipment Manufacturer) đi kèm với thiết bị. Thay vào đó, nó sử dụng công cụ kết xuất hiệu suất cao của riêng mình để vẽ các widget. Nó cũng triển khai hầu hết các hệ thống của nó như hoạt ảnh, cử chỉ và widget bằng ngôn ngữ lập trình Dart cho phép các nhà phát triển đọc, thay đổi, thay thế hoặc loại bỏ mọi thứ một cách dễ dàng. Nó cung cấp khả năng kiểm soát tuyệt vời cho các nhà phát triển đối với hệ thống.

    Các tính năng của Flutter

    Flutter cung cấp các phương pháp dễ dàng và đơn giản để bắt đầu xây dựng các ứng dụng dành cho thiết bị di động và máy tính để bàn đẹp mắt với một bộ thiết kế material design và widget phong phú. Ở đây, chúng ta sẽ thảo luận về các tính năng chính của nó để phát triển framework di động.

     

    Các tính năng của Flutter
    Các tính năng của Flutter
    • Code nguồn mở(Open-Source:): Flutter là một framework code nguồn mở và miễn phí để phát triển các ứng dụng di động.
    • Đa nền tảng(Cross-platform): Tính năng này cho phép Flutter viết code một lần, duy trì và có thể chạy trên các nền tảng khác nhau. Nó tiết kiệm thời gian, công sức và tiền bạc của các nhà phát triển.
    • Tải lại nóng (Hot Reload): Bất cứ khi nào nhà phát triển thực hiện thay đổi trong code, thì những thay đổi này có thể được nhìn thấy ngay lập tức với Tải lại nóng. Nó có nghĩa là những thay đổi hiển thị ngay lập tức trong chính ứng dụng. Đây là một tính năng rất tiện dụng, cho phép nhà phát triển sửa các lỗi ngay lập tức.
    • Các tính năng và SDK gốc có thể truy cập (Accessible Native Features and SDKs): Tính năng này cho phép quá trình phát triển ứng dụng dễ dàng và thú vị thông qua code gốc của Flutter, tích hợp bên thứ ba và các API nền tảng. Do đó, chúng tôi có thể dễ dàng truy cập SDK trên cả hai nền tảng.
    • Code tối thiểu (Minimal code): Ứng dụng Flutter được phát triển bởi ngôn ngữ lập trình Dart, sử dụng biên dịch JIT và AOT để cải thiện thời gian khởi động tổng thể, hoạt động và tăng tốc hiệu suất. JIT nâng cao hệ thống phát triển và làm mới giao diện người dùng mà không cần nỗ lực thêm vào việc xây dựng hệ thống mới.
    • Widget: framework công tác Flutter cung cấp các widget có khả năng phát triển các thiết kế cụ thể có thể tùy chỉnh. Quan trọng nhất, Flutter có hai bộ widget: Material Design và các widget Cupertino giúp mang lại trải nghiệm không có trục trặc trên tất cả các nền tảng.

    Kiến trúc của Flutter

    Kiến trúc Flutter

    Trong phần này, chúng ta sẽ thảo luận về kiến trúc của Flutter framework. Kiến trúc Flutter chủ yếu bao gồm bốn thành phần.

    • Động cơ Flutter (Flutter Engine)
    • Thư viện nền tảng (Foundation Library)
    • Vật dụng (Widgets)
    • Thiết kế các widget cụ thể (Design Specific Widgets)

    Flutter Engine

    Nó là một cổng để giúp chạy các ứng dụng di động chất lượng cao và cơ bản dựa trên ngôn ngữ C ++. Nó triển khai các thư viện lõi Flutter bao gồm animation và đồ họa, tệp và mạng I / O, kiến trúc plugin, hỗ trợ trợ năng và thời gian chạy dart để phát triển, biên dịch và chạy các ứng dụng Flutter. Phải sử dụng thư viện đồ họa mã nguồn mở của Google, Skia, để hiển thị đồ họa cấp thấp.

    Thư viện nền tảng (Foundation Library)

    Nó chứa tất cả các gói cần thiết cho các khối build cơ bản để viết một ứng dụng Flutter. Các thư viện này được viết bằng ngôn ngữ Dart.

    Vật dụng (widget)

    Trong Flutter, mọi thứ đều là một widget, đó là khái niệm cốt lõi của framework. Widget trong Flutter về cơ bản là một thành phần giao diện người dùng ảnh hưởng và kiểm soát chế độ xem và giao diện của ứng dụng. Nó đại diện cho một mô tả bất biến về một phần của giao diện người dùng và bao gồm đồ họa, văn bản, hình dạng và animation được tạo bằng các widget. Các widget tương tự như các thành phần React.

    Trong Flutter, ứng dụng tự nó là một widget chứa nhiều widget con. Điều đó có nghĩa rằng ứng dụng là tiện ích con cấp cao nhất và giao diện người dùng của nó được xây dựng bằng cách sử dụng một hoặc nhiều tiện ích con, bao gồm các tiện ích con phụ. Tính năng này giúp bạn tạo một giao diện người dùng phức tạp rất dễ dàng.

    Kiến trúc Flutter
    Kiến trúc Flutter

    Trong ví dụ trên, chúng ta có thể thấy rằng tất cả các thành phần đều là các widget có chứa các widget con. Do đó, ứng dụng Flutter tự nó là một widget.

    Thiết kế các widget cụ thể

    Framework Flutter có hai bộ widget phù hợp với các ngôn ngữ thiết kế cụ thể. Đây là Material Design cho ứng dụng Android và Cupertino Style cho ứng dụng IOS.

  • KINH NGHIỆM PHỎNG VẤN FLUTTER

    KINH NGHIỆM PHỎNG VẤN FLUTTER

    KINH NGHIỆM PHỎNG VẤN FLUTTER

    Bài này chúng tôi xin chia sẻ một số kinh nghiệm phỏng vấn Flutter, các kiến thức liên quan chúng tôi đều để link đến bài viết tương ứng.

    I. Phỏng vấn Flutter cơ bản

    Đối với phần này, bạn cần nắm và hiểu rõ các kiến thức sau:

    1. Ưu điểm của Flutter
    2. Lifecycle của một Widget
    3. Phân biệt StatelessWidgetStatefulWidget
    4. Các widget thông dụng (Container, Text, Column, Row, Stack, GridView, ListView, SingleScrollView…)
    5. Cách quản lý trạng thái (State Management) của app, bạn có thể sử dụng StatefulWidget hoặc Provider, GetX, Bloc
    6. AOT (Ahead-of-Time) và JIT (Just-in-Time)
    7. Null Safety là gì?
    8. Xử lý bất đồng bộ async trong Dart
    9. Các loại tham số trong hàm của flutter?
    10. Cách sử dụng Key trong Flutter
    11. Cách sử dụng Animation
    12. Phân biệt Widgets, RenderObjects and Elements
    13. Giao tiếp với Backend (SQL, Firebase, Websocket, Logging…)
    14. Testing (BDD, TDD, A/B test…)
    15. Package management + Public to store (iOS + Android)
    16. Null safety để làm gì?
    17. Sự khác nhau httpdio như thế nào?
    18. BlocCubit khác nhau như thế nào?
    19. BlocConsumer dùng để làm gì?
    20. Cách cấp quyền truy cập internet, đọc và ghi dữ liệu…

    Ngoài ra, khi bạn đi phỏng vấn Flutter, người tuyển dụng sẽ chọn một app có sẵn trong điện thoại, sau đó chọn ngẫu nhiên một màn hình và yêu cầu bạn tạo ra UI của màn hình đó.

    II. Phần phỏng vấn Flutter nâng cao

    1. Stream, Isolate, Event Loop, Microtask
    2. Painting Widget
    3. Wrap native lib qua lib Flutter (từ Android hoặc iOS)
    4. Và phần khó nhất của hầu hết mọi dev – Profiling

    III. Một số câu hỏi phỏng vấn Flutter thường gặp

    #Flutter ra đời như thế nào?

    Phiên bản alpha đầu tiên của Flutter đã xuất hiện cách đây gần ba năm – vào tháng 5 năm 2017. Không ai hồi đó nghĩ rằng nó lại trở nên phổ biến trong một khoảng thời gian ngắn như vậy. Nó đã nhận được nhiều “sao” đánh giá trên GitHub hơn đối thủ cạnh tranh lớn nhất của nó là React Native kể từ khi phát hành ổn định vào tháng 12 năm 2018. Nhiều công ty bắt đầu nhận thấy tiềm năng của Flutter và đang tìm kiếm các nhà phát triển sẵn sàng viết ứng dụng.

    #Ai đã tạo ra Flutter?

    Dart được Google tạo ra vào năm 2011. Đây là một ngôn ngữ lập trình mã nguồn mở, có thể mở rộng, với các thư viện và hiệu suất chạy khá tốt, để xây dựng web, máy chủ và ứng dụng di động. Flutter là một Framework sử dụng ngôn ngữ lập trình Dart để xây dựng các ứng dụng di động.

    #Dart là gì?

    Dart là một ngôn ngữ lập trình hướng đối tượng, có mục đích chung với cú pháp kiểu C. Nó là mã nguồn mở và được phát triển bởi Google vào năm 2011. Mục đích của lập trình Dart là tạo giao diện người dùng frontend cho web và ứng dụng di động. Nó là một ngôn ngữ quan trọng để tạo ứng dụng Flutter. Ngôn ngữ Dart có thể được biên dịch cả AOT (Ahead-of-Time) và JIT (Just-in-Time).

    #Flutter có miễn phí không?

    Có. Flutter là miễn phí và mã nguồn mở.

    #Ưu điểm của Flutter là gì?

    Các ưu điểm phổ biến của Flutter framework như sau:

    • Phát triển đa nền tảng: Tính năng này cho phép Flutter viết code một lần, duy trì và có thể chạy trên các nền tảng khác nhau (mobile, desktop, web…) Nó tiết kiệm thời gian, công sức và tiền bạc của các nhà phát triển.
    • Phát triển nhanh hơn: Hiệu suất của ứng dụng Flutter rất nhanh. Flutter biên dịch ứng dụng bằng cách sử dụng thư viện nhánh C / C ++ giúp ứng dụng gần với code máy hơn và mang lại cho ứng dụng hiệu suất gốc tốt hơn.
    • Cộng đồng tốt: Flutter có hỗ trợ cộng đồng tốt, nơi các nhà phát triển có thể hỏi các vấn đề và nhận được kết quả nhanh chóng.
    • Tải lại trực tiếp và nóng: Nó làm cho quá trình phát triển ứng dụng cực kỳ nhanh chóng. Tính năng này cho phép chúng tôi thay đổi hoặc cập nhật code được phản ánh ngay sau khi các thay đổi được thực hiện.
    • code tối thiểu: Ứng dụng Flutter được phát triển bởi ngôn ngữ lập trình Dart, sử dụng biên dịch JIT và AOT để cải thiện thời gian khởi động tổng thể, hoạt động và tăng tốc hiệu suất. JIT nâng cao hệ thống phát triển và làm mới giao diện người dùng mà không cần nỗ lực thêm vào việc xây dựng hệ thống mới.
    • Tập trung vào giao diện người dùng: Nó có giao diện người dùng tuyệt vời vì nó sử dụng widget tập trung vào thiết kế, các công cụ phát triển cao, API nâng cao và nhiều tính năng khác.
    • Tài liệu: Flutter có hỗ trợ tài liệu rất tốt. Nó được tổ chức và nhiều thông tin hơn. Chúng ta có thể lấy mọi thứ mà chúng ta muốn viết ở một nơi.

    #Null Safety là gì?

    #Widget trong Flutter là gì?

    Một ứng dụng Flutter luôn được coi là một cây các material. Bất cứ khi nào bạn định viết code để xây dựng bất cứ thứ gì trong Flutter, nó sẽ nằm bên trong một widget. Các widget mô tả chế độ xem ứng dụng của bạn trông như thế nào với cấu hình và trạng thái hiện tại của chúng. Khi bạn thực hiện bất kỳ thay đổi nào trong code, widget con sẽ xây dựng lại mô tả của nó bằng cách tính toán sự khác biệt của widget con hiện tại và trước đó để xác định những thay đổi tối thiểu đối với việc hiển thị trong giao diện người dùng của ứng dụng.

    Các widget được lồng vào nhau để xây dựng ứng dụng. Nó có nghĩa là thư mục gốc của ứng dụng của bạn tự nó là một widget và tất cả các cách nhìn xuống cũng là một widget. Ví dụ: một widget có thể hiển thị một cái gì đó, có thể xác định thiết kế, có thể xử lý tương tác, v.v.

    #Sự khác biệt giữa stateless và stateful widget là gì?

    Các stateless widget chúng chỉ được tạo một lần, do đó trong phương thức build cũng chỉ được gọi một lần. Ngược lại stateful widget có thể được rebuild lại khi có giá trị thay đổi.

    #Vòng đời của StatefulWidget là gì?

    • createState() – một phương thức trong một phương thức StatefulWidget được gọi ngay lập tức và sẽ trả về một State của các đối tượng widget.
    • initState() – phương thức đầu tiên được gọi trong State widget sau khi widget được tạo.
    • didChangeDependencies() – được gọi ngay sau initState() lần đầu tiên được gọi.
    • build() – rất giống với từ StatelessWidget . Nó được gọi ngay sau đó didChangeDependencies(). Nó được gọi mỗi khi giao diện người dùng cần hiển thị và trả về widget tree.
    • didUpdateWidget() – nó được gọi khi widget đã thay đổi và cần vẽ lại giao diện người dùng của nó
    • deactivate() – được gọi trước dispose() , khi đối tượng này được xóa ra khỏi cây widget.
    • dispose() – được gọi khi widget đã bị xóa khỏi state và không thể khởi tạo lại.

    #SafeArea widget là gì?

    Đây là một widget bao ngoài tất cả widget khác, mục đích là để nó không chiếm vào thanh thông báo của thiết bị, ứng dụng sẽ nằm ở dưới thanh thông báo.

    #Flutter chỉ dành cho ứng dụng di động?

    Không, bạn cũng có thể xây dựng các ứng dụng web – mặc dù nó vẫn đang trong giai đoạn thử nghiệm và chưa được phát hành chính thức.

    #Những cách nào để tạo navigation?

    #Flutter có thực sự là native không?

    Ứng dụng Flutter được biên dịch thành một thư viện ARM và x86 native, vì vậy, về mặt kỹ thuật, nó như là native.

    #Làm cách nào để bạn đặt kích thước widget dựa trên kích thước màn hình?

    Sử dụng hàm MediaQuery.of(context).size

    #Lệnh để cập nhật tất cả các plugin là gì?

    flutter pub upgrade

    #Lập trình bất đồng bộ trong Dart (Flutter) như thế nào? Future trong Flutter là gì?

    #Factory trong Flutter là gì?

    https://api.flutter.dev/flutter/foundation/Factory-class.html

    #Các loại tham số trong hàm flutter?

    https://www.youtube.com/watch?v=n5eix5aeZvg

    #Phân biệt constfinal

    #Tệp pubspec.yml là gì?

    Đó là một tệp mà bạn có thể khai báo sử dụng tất cả các thư viện, plugin, font chữ, hình ảnh… của dự án Flutter của bạn. Đó cũng là nơi bạn định cấu hình tên và mô tả của dự án. Tệp này chứa:

    • Cài đặt chung của dự án như tên, mô tả và phiên bản của dự án.
    • Sự phụ thuộc của dự án.
    • Nội dung dự án (ví dụ: hình ảnh, âm thanh, v.v.).

    #Tập tin AndroidManifest.xml là gì?

    #Tập tin Info.plist là gì?

    #Làm cách nào để bạn đặt biểu tượng ứng dụng trong Android và iOS?

    #Làm thế nào để tạo một TextField với giá trị ban đầu?

    Chúng ta cần đặt một controller với giá trị ban đầu:

    • TextEditingController(text: ‘Giá trị ban đầu’); .
    • FocusScope.of(context).unfocus();

    #Làm thế nào để bạn tải một hình ảnh từ mạng?

    Để hiển thị hình ảnh từ một URL, chúng ta có thể sử dụng hàm Image.network()

    #Làm thế nào để bạn ghi đè nút back trên thiết bị?

    Chúng ta có thể sử dụng WillPopScope widget cho việc này.

    #Mục đích của thuộc tính reverse trên một ListView widget là gì?

    Nó hiển thị các item trong ListView theo thứ tự đảo ngược.

    #Tween Animation là gì?

    Đây là hình thức rút gọn của in-betweening. Trong hoạt ảnh tween, bắt buộc phải xác định điểm đầu và điểm cuối của hoạt ảnh. Nó có nghĩa là hoạt ảnh bắt đầu với giá trị bắt đầu, sau đó đi qua một loạt các giá trị trung gian và cuối cùng đạt đến giá trị kết thúc. Nó cũng cung cấp dòng thời gian và đường cong, xác định thời gian và tốc độ của quá trình chuyển đổi. framework công cụ cung cấp tính toán về cách chuyển đổi từ điểm đầu và điểm cuối.

    #Stream trong Flutter là gì?

    Luồng là một chuỗi các sự kiện không đồng bộ. Nó cung cấp một chuỗi dữ liệu không đồng bộ. Nó cũng giống như một đường ống mà chúng ta đặt một số giá trị vào một đầu và nếu chúng ta có một người nghe ở đầu kia, nó sẽ nhận được giá trị đó. Chúng tôi có thể giữ nhiều người nghe trong một luồng và tất cả những người nghe đó sẽ nhận được cùng một giá trị khi được đưa vào đường dẫn.

    (Các câu hỏi khác mời bạn xem trong bài Các câu hỏi phỏng vấn Flutter)

  • Class in Dart / Flutter

    Class in Dart / Flutter

    Class in Dart/Flutter

    What is class in Dart?

    • In object-oriented programming, a class is a blueprint for creating objects (a particular data structure), providing initial values for state (member variables or attributes), and implementations of behavior (member functions or methods).
    • We can assume a class as a sketch (prototype) or a car. It contains all the details about model name, year, features, price, etc. Based on these properties of the car, we can build the car. Here the car is an object.
    • There can be many cars so we can create many objects of cars to access all the properties.

    what is class in dart flutter

    Benefit of object-oriented programming

    • Modularity: The source code of an object can be maintained individually and can hide from the other object’s source code.
    • Data – hiding: Using oops programming, the details of the internal functionality of code are hidden from the others. For example – Users only interact with the application, but they don’t familiar with the internal implementation.
    • Reusability: We don’t need to write the same code again and again. We can use the object of class multiple times in our program.
    • Pluggability and debugging easy: If any object is creating a problem in our program, and then we can replace it in our program and plug the new object as its replacement. The oops code can be easy to debug.

    Defining a Class in Dart

    Dart provides class keyword followed by a ClassName is used to define a class; all fields and functions are enclosed by the pair of curly braces {}.

    class ClassName {
      <fields/properties>
      <getters/setters>
      <constructors>
      <functions>
    }
    • <fields/properties> any variable declared in a class, represent data pertaining to objects.
    • <getters/setters> initialize and retrieve the values of the fields of a class
    • <constructors> responsible for allocating memory for the objects of the class.
    • <functions> represent actions an object can take

    class in dart

    Creating Instance of the class

    • To create an instance of the class, use the new keyword followed by the class name.

    var object_name = new ClassName([arguments])

    • The new keyword is responsible for instantiation. Starting from Dart 2, the keyword new can be omitted.
    • The right-hand side of the expression invokes the constructor.
    • The constructor should be passed values if it is parameterized.

    Libraries and visibility

    • a library referring to the code inside a file with the .dart extension
    • to use that particular library, you have to reference its content with the import keyword
    • using the as keyword if have two different libraries have implemented a class with the same name
    • selectively import or exclude types using the show and hide keywords

    Class Constructors

    A constructor is a special function of the class that is responsible for initializing the variables of the class. Dart defines a constructor with the same name as that of the class. A constructor is a function and hence can be parameterized. However, unlike a function, constructors cannot have a return type.

    👉Named and positional parameters in Dart

    Class_name(parameter_list) {
    //constructor body
    //.............
    }
    • If your class doesn’t define a constructor, the compiler automatically adds a default constructor with no parameters and an empty body.
    • The “initializing formal” using this keyword, more readable and it initializes the variables immediately
    • With null safety, a named argument with a non-nullable type must either have a default or be marked with the new required keyword. Otherwise, it wouldn’t make sense for it to be non-nullable, because it would default to null when not passed.
    • With the “initializing formal” you can still declare a body to perform additional setup for the class, constructors cannot have a return type.
    • If you don’t declare a constructor, a default no-argument constructor is provided for you.

    Initializer list

    • When using the initializing formal approach, the names of the variables must match the ones declared in the constructor.
    • If you wanted to keep fields private but with a different name in the constructor, use an initializer list
    class Test {
    int _secret;
    double _superSecret;
    Test(int age, double wallet)
    : _secret = age,
    _superSecret = wallet;
    }

    Named Constructors

    Named constructors are generally used to implement a default behavior the user expects from your class. They are the only alternative to have multiple constructors since Dart has no method overload.

    Class_name.constructor_name(param_list)

    Redirecting constructors

    Sometimes you might have a constructor that does almost the same thing already implemented by another one. It may be the case to use redirecting constructors in order to avoid code duplication.

    Factory constructors

    • The factory keyword returns an instance of the given class that’s not necessarily a new one. It can be useful when:
      • you want to return an instance of a subclass instead of the class itself,
      • you want to implement a singleton (the Singleton pattern),
      • you want to return an instance from a cache.
    • Factory constructors are like static methods and so they don’t have access to this. There cannot be together a factory and a “normal” constructor with the same name.

    static variables and methods

    • The static keyword can be applied to the data members of a class, i.e., fields and methods. A static variable retains its values till the program finishes execution. Static members are referenced by the class name.
    • The static variables and methods are part of the class instead of a specific instance.
    • The static keyword is used for a class-level variable and method that is the same for every instance of a class, this means if a data member is static, it can be accessed without creating an object.
    • The static keyword allows data members to persist values between different instances of a class.
    • There is no need to create a class object to access a static variable or call a static method: simply put the class name before the static variable or method name to use them.

    The this keyword

    The this keyword refers to the current instance of the class. Here, the parameter name and the name of the class’s field are the same. Hence to avoid ambiguity, the class’s field is prefixed with the this keyword.

    Accessing Attributes and Functions

    A class’s attributes and functions can be accessed through the object. Use the “.” dot notation (called as the period) to access the data members of a class.

    //accessing an attribute
    obj.field_name
    //accessing a function
    obj.function_name()

    Cascade notation

    • The cascade notation (..) in Dart allows you to make a sequence of operations on the same object (including function calls and field access).
    • This notation helps keep Dart code compact and removes the need to create temporary variables to store data.

    Encapsulation (Access modifiers)

    • In Java, we can use public, protected, and private keywords to control the access scope for a property or method. However, Dart doesn’t provide that
      kind of keywords. Instead, you can use _ (underscore) at the start of the name to make a data member of a class becomes private.
    • In Dart, the privacy is at library level rather than class level. It means other classes and functions in the same library still have the access. So, a data member is either public (if not preceded by _) or private (if preceded by _)

    Getters and Setters

    • Getters and Setters, also called as accessors and mutators, allow the program to initialize and retrieve the values of class fields respectively. Getters or accessors are defined using the get keyword. Setters or mutators are defined using the set keyword.
    • A default getter/setter is associated with every class. However, the default ones can be overridden by explicitly defining a setter/ getter. A getter has no parameters and returns a value, and the setter has one parameter and does not return a value.

    Class Inheritance

    • Dart supports the concept of Inheritance which is the ability of a program to create new classes from an existing class. The class that is extended to create newer classes is called the parent class/super class. The newly created classes are called the child/sub classes.
    • A class inherits from another class using the extends keyword. Child classes inherit all properties and methods except constructors from the parent class.

    Types of Inheritance

    • Inheritance can be of the following three types:
    • Single – Every class can at the most extend from one parent class.
    • Multiple – A class can inherit from multiple classes. Dart doesn’t support multiple inheritance.
      Multi-level – A class can inherit from another child class.

    Class Inheritance and Method Overriding

    • Method Overriding is a mechanism by which the child class redefines a method in its parent class.

    super keyword

    • The super keyword is used to refer to the immediate parent of a class.
    • The super keyword can be used to refer to the super class version of a variable, property, or method.

    super and constructors

    Every subclass in Dart automatically tries to call the default constructor of the superclass. If there isn’t one, you must call the superclass constructor
    manually in the initializer list.

    Abstract class

    • The abstract keyword defines a class that cannot be directly instantiated: only its derived classes can. An abstract class can define one (or more)
      constructors as usual.
    • Usually abstract classes contain abstract methods which can be defined putting a semicolon (;) instead of the body. You cannot define an abstract
      method in a class that’s not been marked with the abstract modifier.
    • If your class contains at least one method with no body, then it must be abstract and the children must provide an implementation.

    Interfaces

    • In contrast to other programming languages, Dart does not have an interface keyword and you have to use classes to create interfaces. Your class can
      implement more than a single interface.
    • The keyword is implements and, differently from a regular subclass, here you must override every method defined by the class/interface.
    • In Dart when you use the term interface you are referring to a class that is going to be used by others along with implements because it only provides method signatures. The concept is the same you can find in Java, Delphi or C# with the only difference that Dart doesn’t have a dedicated keyword.
    • While extends can be used with only one class, implements works with one or more classes, which you should treat as interfaces (methods with no body).

    extends vs implements

    • When you use class B extends A {} you are NOT forced to override every method of class A. Inheritance takes place and you can override as many methods as you want. This is the typical OOP inheritance that can be used when you want to add some missing features in a subclass.
    • When you use class B implements A {} you must override every method of class A. Inheritance does NOT take place because methods just provide an API, a “skeleton” that the subclass must concretize.
    • Interfaces are useful when you don’t want to provide an implementation of the functions but just the API. It’s like if the interface was wall socket and the class was the plug that adapts to the holes. While multiple inheritance is not allowed, you can extends a class and implements more than one.

    Mixins

    • a mixin is simply a class with no constructor that can be “attached” to other classes to reuse the code without inheritance
    • mixins like a “copy/paste” tool to reuse methods

    override operators

    • Operator overloading gives the possibility to customize the usage of operators in your classes.
    • Arithmetic operators like +, -, *, or /.
    • Relational operators such as >=, <=, > or <.
    • Equality operators like != and ==

    callable classes

    There is a special call() method which is very closely related to an operator overload because it allows classes to be called like if they were functions with
    the () operator.

  • Named and positional parameters in Dart

    Named and positional parameters in Dart

    Named and positional parameters in Dart

    In Dart, we have two types of optional parameters: named and positional.

    • Dart’s optional parameters are optional in that the caller isn’t required to specify a value for the parameter when calling the function.
    • Optional parameters can only be declared after any required parameters.
    • Optional parameters can have a default value, which is used when a caller does not specify a value.

    Optional parameters are parameters which don’t have to be specified when calling given function. Optional parameters must be declared after required parameters. Additionally, optional parameters can have a default value, which is used once the function invocation doesn’t specify it.

    👉Dart Cheat Sheet and Quick Reference

    Positional Parameters in Dart

    Square brackets [] are used to specify optional, positional parameters in Dart.

    void hamViDu(int a, [int b = 0, int c = 0]) {
      if (b != 0 && c != 0) {
        print('a:$a - b:$b - c:$c');
      } else if (b != 0) {
        print('a:$a - b:$b');
      } else {
        print('a:$a');
      }
    }
    
    void main() {
      hamViDu(5, 10, 15);
    
      print('----------------------');
      hamViDu(5);
    
      print('----------------------');
      hamViDu(5, 10);
    }

    For such declaration a is always required while b and c are optional. Also, b, c will default to 0 if not specified.

    hamViDu(5, 10, 15); //print a:5 - b:10 - c:15
    
    hamViDu(5); //print a:5
    
    hamViDu(5, 10);//print a:5 - b:10

    Additionally, the parameter names are specified and visible only at the level of the function declaration. The function caller must know which position corresponds to which parameter. This leads to a slightly less readable code.

    Named parameters in Dart

    Curly brackets {} are used to specify optional, named parameters in Dart.

    readFile(String name, {String mode, String charset = 'utf-8'}) { 
    //......
    }

    Named parameters are referenced by name, which means that they can be used during the function invocation in an order different from the function declaration.

    void hamViDu({int a = 0, int b = 0, int c = 0}) {
      print('a:$a - b:$b - c:$c');
    }
    
    void main() {
      hamViDu();
    
      print('----------------------');
      hamViDu(a: 5, c: 15, b: 10);
    
      print('----------------------');
      hamViDu(c: 5);
      
      print('----------------------');
      hamViDu(b: 5, c: 10);
    }

    Checking if optional parameter was provided

    Unfortunately, you cannot distinguish between the cases “an optional parameter was not provided” and “an optional parameter was provided with the default value”.

    Note: You may use positional optional parameters or named optional parameters, but not both in the same function or method. The following is not allowed.

    thisFunctionWontWork(String foo, [String positonal], {String named}) {
     // will not work! 
    }
  • Kiểu null trong Dart

    Kiểu null trong Dart

    Kiểu null trong Dart là một đối tượng đặc biệt dùng để biểu thị cho một đối tượng rỗng, trống, không chứa gì.

    Trước phiên bản 2.0 thì khi tạo mới một biến, Dart sẽ gán giá trị mặc định cho biến đó là null, nếu không được cung cấp.

    Từ phiên bản 2.0 trở đi thì Dart hỗ trợ tính năng null safety, do đó bạn cần cung cấp cho biến một giá trị trước khi sử dụng biến đó, nếu không Dart sẽ cảnh báo ngay trong khi soạn thảo mà không cần đợi đến khi biên dịch chương trình. Chi tiết, xin mời xem trong bài 🎯 Null safety Dart / Null safety Flutter là gì?

    Có một số toán tử đặc biệt làm việc với giá trị null??!

  • Kiểu logic bool trong Dart

    Kiểu logic bool trong Dart

    Kiểu logic bool trong Dart

    Kiểu logic bool trong Dart (kiểu Boolean) sử dụng từ khóa bool để khai báo.

    Kiểu dữ liệu bool trong Dart có 2 giá trị là true (đúng) và false (sai) được sử dụng để thể hiện kết quả của một mệnh đề logic (các phép toán so sánh, kiểm tra, các hàm…)

    void main() {
     
      print(1 > 2);// kết quả false
      print((1/0).isInfinite);// kết quả true
    
      var s = ''; 
      print(s.isEmpty);// kết quả true
    
      print(true & false); // kết quả false
      print(true | false); // kết quả false
      print(!true); // kết quả false
    }

    Trong Dart, giá trị 1 hoặc 0 không được sử dụng để thay thế truefalse như trong các ngôn ngữ khác.

    Các phép toán trên kiểu bool trong Dart gồm có and &, or | và not !. Bạn có thể xem chi tiết ở bài Các phép toán trong Dart (Toán tử Dart/Flutter)

    toan tu bool trong Python Toán tử Boolean trong Python

  • Deploy Flutter web app to Firebase Hosting

    Deploy Flutter web app to Firebase Hosting

    Step 1: Create a project on Firebase console
    Step 2: Download Firebase CLI from here  Firebase CLI binary for Windows.
    Step 3: Login via CLI, execute the command firebase login

    Deploy Flutter web app to Firebase Hosting 6

    Step 4: Choose Firebase “Hosting” for Flutter web app when asked for a feature

    Deploy Flutter web app to Firebase Hosting 7

    Step 5: Then, Select an existing Project

    Deploy Flutter web app to Firebase Hosting 8

    Step 6: Choose build/web as a directory & configure as a single-page app

    Deploy Flutter web app to Firebase Hosting 9

    If you see, File build/web/index.html already exists. Overwrite?
    Then select NO. So it will not generate a default index.html file

    Step 7: Deploy Flutter web to Firebase!

    firebase deploy
    Deploy Flutter web app to Firebase Hosting 10