| Animation trong Flutter: Thổi hồn vào ứng dụng (60fps)

Được viết bởi thanhdt vào ngày 28/01/2026 lúc 07:37 | 54 lượt xem

Một ứng dụng tốt chỉ cần chạy đúng logic. Nhưng một ứng dụng đẳng cấp thì phải khiến người dùng cảm thấy “sướng” khi chạm vào.

Bí mật nằm ở Animation. Từ một hiệu ứng trượt nhẹ, một cú nảy đàn hồi, đến một biểu tượng loading quay tít – tất cả tạo nên trải nghiệm người dùng (UX) mượt mà. Trong Flutter, làm animation dễ hơn bạn nghĩ.

1. Implicit Animation: Mì ăn liền

Nếu bạn chỉ muốn:“Khi user bấm nút, cái hộp đổi màu từ đỏ sang xanh”, hãy dùng Implicit Animation.
Bạn không cần quan tâm đến Controller hay Ticks, chỉ cần đổi giá trị, Flutter sẽ tự vẽ phần chuyển động ở giữa.

Ví dụ với AnimatedContainer:

AnimatedContainer(
  duration: Duration(seconds: 1), // Thời gian chuyển đổi
  curve: Curves.fastOutSlowIn,    // Hiệu ứng gia tốc
  width: _selected ? 200.0 : 100.0,
  color: _selected ? Colors.blue : Colors.red,
  child: FlutterLogo(size: 75),
)

2. Explicit Animation: Kiểm soát tuyệt đối

Khi bạn cần: “Cái hộp xoay 3 vòng, dừng lại 1 giây, rồi phình to ra, sau đó lặp lại mãi mãi”. Implicit bó tay. Lúc này cần Explicit Animation.

Bạn sẽ làm việc với AnimationController. Nó giống như một cái đồng hồ đếm giờ chạy từ 0.0 đến 1.0.

Đồ thị giá trị của Animation Controller theo thời gian

class MySpinner extends StatefulWidget { ... }

class _MySpinnerState extends State<MySpinner> with SingleTickerProviderStateMixin {
  late AnimationController _controller;

  @override
  void initState() {
    _controller = AnimationController(
      duration: const Duration(seconds: 2),
      vsync: this,
    )..repeat(); // Chạy lặp lại
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return RotationTransition(
      turns: _controller,
      child: const Icon(Icons.refresh, size: 50),
    );
  }
}

3. Lottie: Đỉnh cao Animation không cần Code

Bạn không giỏi toán để vẽ các đường cong Bezier? Đừng lo. Hãy nhờ Designer vẽ trên After Effects, xuất ra file JSON (Lottie), và ném vào Flutter.

Quy trình Lottie: After Effects -> JSON -> Flutter App

Cài gói lottie:

dependencies:
  lottie: ^2.7.0

Sử dụng:

Lottie.asset('assets/delivery_truck.json')

4. Mẹo tăng hiệu năng (Performance)

Animation đẹp mà giật lag thì vứt.
– Dùng const Widget bất cứ khi nào có thể.
– Tránh dùng setState ở widget cha quá cao trong cây Widget.
– Với Explicit Animation, hãy dùng AnimatedBuilder để chỉ vẽ lại phần cần thiết.


Chúng ta đã đi qua 9 bài học cốt lõi của Flutter. Từ cài đặt, Widget, State Management, API, Database đến Animation. Hành trang của bạn đã khá đầy đủ rồi.

Bài cuối cùng: Học xong rồi thì làm gì? Lộ trình sự nghiệp và Khóa học chuyên sâu.

👉 Tổng kết Series: Điểm đến tiếp theo cho sự nghiệp Flutter Dev


💡 Bạn muốn học cách tạo hiệu ứng Hero Animation, Custom Painter vẽ biểu đồ phức tạp?
Tất cả kỹ thuật UI nâng cao đều có trong: Khóa học Lập trình Flutter Thực chiến

| Xử lý ảnh & media trong Flutter: Camera, Image Picker & Permission

Được viết bởi thanhdt vào ngày 28/01/2026 lúc 07:35 | 52 lượt xem

Trong thời đại “sống ảo” lên ngôi, tính năng đổi Avatar, chụp ảnh check-in gần như là bắt buộc với mọi ứng dụng Mobile.

Nhưng làm sao để truy cập Camera và Thư viện ảnh của điện thoại một cách an toàn? Làm sao để xin quyền (Permission) mà không bị Apple từ chối duyệt App? Bài viết này là chìa khóa cho bạn.

1. Quy trình chọn ảnh chuẩn (Workflow)

Để lấy được một tấm ảnh từ người dùng, chúng ta cần đi qua các bước sau:

  1. User Trigger: Người dùng bấm nút “Đổi Avatar”.
  2. Permission Check: App kiểm tra xem đã được cấp quyền chưa.
  3. System Picker: Mở giao diện chọn ảnh của hệ điều hành.
  4. Result: Nhận về đường dẫn file (File Path) để hiển thị hoặc Upload.

2. Cài đặt thư viện & Cấu hình

Thư viện quốc dân: image_picker.
Thêm vào pubspec.yaml:

dependencies:
  image_picker: ^1.0.4

Cấu hình quyền (Cực quan trọng)

Nếu quên bước này, App sẽ bị Crash ngay lập tức khi mở Camera!

Hộp thoại xin quyền trên iOS/Android

  • iOS (Info.plist):
<key>NSCameraUsageDescription</key>
<string>Chúng tôi cần Camera để bạn chụp ảnh đại diện</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>Chúng tôi cần truy cập thư viện để bạn chọn ảnh</string>
  • Android (AndroidManifest.xml):
    Từ Android 10 trở lên, bạn không cần xin quyền đọc bộ nhớ nếu dùng System Picker, nhưng quyền Camera thì vẫn cần nếu bạn tự build giao diện chụp.

3. Code thực chiến: Chọn ảnh và hiển thị

Dưới đây là đoạn code mẫu để chọn ảnh từ thư viện và hiển thị lên màn hình.

import 'dart:io';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';

class AvatarPicker extends StatefulWidget {
  @override
  _AvatarPickerState createState() => _AvatarPickerState();
}

class _AvatarPickerState extends State<AvatarPicker> {
  File? _image;
  final picker = ImagePicker();

  Future getImage() async {
    // Gọi System Picker
    final pickedFile = await picker.pickImage(source: ImageSource.gallery);

    setState(() {
      if (pickedFile != null) {
        _image = File(pickedFile.path); // Lưu đường dẫn
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        _image == null
            ? Text('Chưa chọn ảnh nào')
            : Image.file(_image!), // Hiển thị ảnh từ File
        ElevatedButton(
          onPressed: getImage,
          child: Icon(Icons.add_a_photo),
        ),
      ],
    );
  }
}

4. Nâng cao: Cắt ảnh (Image Cropper)

Ảnh người dùng chụp thường có tỉ lệ lung tung. Để App đẹp, bạn nên buộc họ cắt ảnh về hình vuông hoặc tỉ lệ 16:9.
Thư viện khuyên dùng: image_cropper.

Giao diện cắt ảnh (Crop UI) chuyên nghiệp

File? croppedFile = await ImageCropper().cropImage(
    sourcePath: imagePath,
    aspectRatioPresets: [
      CropAspectRatioPreset.square,
      CropAspectRatioPreset.ratio16x9,
    ],
    uiSettings: [
      AndroidUiSettings(
          toolbarTitle: 'Cắt ảnh',
          toolbarColor: Colors.deepOrange,
          toolbarWidgetColor: Colors.white,
          initAspectRatio: CropAspectRatioPreset.original,
          lockAspectRatio: false),
      IOSUiSettings(
        title: 'Cắt ảnh',
      ),
    ],
);

Đã có ảnh đẹp, giao diện mượt, nhưng App vẫn cảm thấy “cứng đơ”? Đó là do thiếu Animation.

Bài tiếp theo: Animation cơ bản trong Flutter: Thổi hồn vào ứng dụng.

👉 Cách tạo hiệu ứng chuyển động mượt mà 60fps


💡 Bạn muốn học cách Upload ảnh lên Server AWS S3 hoặc Firebase Storage?
Module Upload File nâng cao có trong: Khóa học Lập trình Flutter Thực chiến

| Tại sao Bot Auto Trading cần Backend FastAPI? (Góc nhìn hệ thống)

Được viết bởi thanhdt vào ngày 28/01/2026 lúc 07:34 | 201 lượt xem

Bot Auto Trading không chỉ là một đoạn code đặt lệnh đơn giản. Nó là một hệ thống backend phức tạp xử lý dữ liệu, tín hiệu, quản lý rủi ro và trạng thái giao dịch.

Trong bài viết này, chúng ta sẽ đi sâu vào lý do tại sao FastAPI lại là “bộ não” không thể thiếu cho một hệ thống trading chuyên nghiệp, thay vì chỉ dùng các script Python rời rạc.

1. Hiểu đúng: Bot Auto Trading KHÔNG chỉ là script Python

Rất nhiều bạn mới học làm bot thường bắt đầu bằng cách:
1. Viết 1 file bot.py.
2. Lấy dữ liệu nến từ sàn.
3. Tính chỉ báo (RSI, MACD) -> Có tín hiệu thì đặt lệnh.
4. Chạy vòng lặp while True.

Vấn đề: Cách này chỉ chạy được Demo hoặc 1 tài khoản cá nhân. Khi bạn muốn chạy 5 chiến lược cùng lúc, quản lý 10 tài khoản, hay build dashboard theo dõi, file script đó sẽ trở thành “đống rác” không thể bảo trì.

👉 Giải pháp: Bạn cần một Backend đúng nghĩa.

2. Backend trong hệ thống Bot Auto Trading làm gì?

Một hệ thống trading tiêu chuẩn (Institutional Grade) sẽ có kiến trúc như sau:

Kiến trúc hệ thống Bot Auto Trading chuyên nghiệp với FastAPI làm trung tâm

Thành phần Vai trò
TradingView / AI Sinh tín hiệu (Signal Generator)
FastAPI Backend Bộ não trung tâm: Nhận tín hiệu, xử lý logic, điều phối
Risk Engine Lá chắn: Kiểm tra hạn mức lỗ, size lệnh, kill-switch
Exchange API Cánh tay: Thực thi lệnh mua/bán (Binance, Bybit…)
Database Bộ nhớ: Lưu lịch sử lệnh, trạng thái (State)

👉 FastAPI nằm ở chính giữa, nhận tín hiệu từ mọi nơi và điều phối hành động.

3. Tại sao FastAPI là “Chân Ái” cho Bot Trading?

✅ 1. Tốc độ cao (High Performance)

Trader tính bằng mili-giây. FastAPI được xây dựng trên StarletteASGI, hỗ trợ Async/Await tận răng.
Nó có thể xử lý hàng nghìn tín hiệu Webhook cùng lúc mà không bị nghẽn (Block) như Django hay Flask thuần.

✅ 2. Nhận Webhook TradingView chuẩn chỉnh

Đây là tính năng quan trọng nhất. FastAPI định nghĩa API rất rõ ràng:

Luồng xử lý Webhook của FastAPI: Nhận -> Validate -> Xử lý

from fastapi import FastAPI, Request

app = FastAPI()

@app.post("/webhook/tradingview")
async def receive_signal(request: Request):
    # 1. Nhận JSON từ TradingView
    data = await request.json()

    # 2. Đẩy vào hàng đợi xử lý (để trả lời TradingView ngay lập tức)
    await process_order_queue(data)

    return {"status": "received"}

✅ 3. Quản lý trạng thái (Stateful System)

Bot cần biết: Hiện tại đang lãi hay lỗ? Có lệnh nào đang treo không?
FastAPI kết hợp với Database (PostgreSQL/Redis) để lưu giữ “Trạng thái”. Nếu Bot bị khởi động lại, nó vẫn biết mình đang làm gì tiếp theo, không bị mất trí nhớ.

✅ 4. Quản lý rủi ro (Risk Management)

Một con bot chỉ biết đặt lệnh là một con bot “ngu ngốc”. Backend FastAPI cho phép bạn chèn logic bảo vệ tài khoản trước khi lệnh được gửi ra sàn:
if daily_loss > 5%: Dừng toàn bộ bot.
if open_orders > 10: Không vào thêm lệnh mới.
Những logic này rất khó cài cắm nếu chỉ dùng script đơn giản.

4. Khi nào BẮT BUỘC phải dùng Backend FastAPI?

Bạn nên chuyển sang kiến trúc này nếu:
– 🚀 Trade theo tín hiệu Webhook từ TradingView.
– 📈 Chạy nhiều chiến lược (Strategy) trên cùng một tài khoản.
– 👥 Quản lý nhiều tài khoản (Copy Trade).
– 📊 Cần có Dashboard để theo dõi lãi lỗ Realtime.
– 🛡️ Muốn hệ thống chạy 24/7 ổn định, tự khởi động lại khi lỗi.

5. Kết luận

Đừng mãi là một “Script Kiddie” với những file .py lộn xộn. Hãy tư duy như một System Architect.

Hệ thống Bot Auto Trading là sự kết hợp giữa Tài chính (Finance)Công nghệ (Tech). Và FastAPI chính là cầu nối vững chắc nhất để hiện thực hóa các ý tưởng giao dịch của bạn thành một cỗ máy kiếm tiền tự động.


💡 Bạn muốn tự tay xây dựng hệ thống Bot Trading đa nền tảng (Binance, Telegram, Webhook)?
Tham khảo ngay khóa học chuyên sâu: Lập trình Bot Auto Trading Đa Nền Tảng

| Lưu trữ local trong Flutter: SharedPreferences & SQLite để App chạy Offline

Được viết bởi thanhdt vào ngày 28/01/2026 lúc 07:29 | 50 lượt xem

Một ứng dụng tốt là ứng dụng vẫn hoạt động (một phần) ngay cả khi mất mạng. Để làm được điều đó, bạn cần biết cách lưu trữ dữ liệu ngay trên thiết bị của người dùng (Local Storage).

Nhưng giữa ma trận: SharedPreferences, SQLite, Hive, Drift…, bạn nên chọn cái nào? Bài viết này sẽ giúp bạn chọn đúng công cụ cho đúng việc.

Công cụ Loại dữ liệu Thích hợp cho Tốc độ
SharedPreferences Key-Value đơn giản Cài đặt App, Token đăng nhập Cực nhanh
SQLite (sqflite) Có cấu trúc (Table) Danh sách sản phẩm, Tin nhắn Nhanh
Hive NoSQL Dữ liệu lớn cần tốc độ cao Siêu nhanh

1. SharedPreferences: Két sắt mini

Hãy tưởng tượng SharedPreferences giống như một tập file ghi chú nhỏ. Bạn dùng nó để lưu những thông tin đơn giản như: “User này có thích giao diện tối không?”, “Token đăng nhập là gì?”.

Cách dùng:

Đừng lạm dụng nó để lưu cả một danh sách 1000 sản phẩm nhé! Nó sẽ làm App bạn chậm rì đấy.

// Lưu dữ liệu
final prefs = await SharedPreferences.getInstance();
await prefs.setBool('isDarkMode', true);

// Lấy dữ liệu
final isDark = prefs.getBool('isDarkMode') ?? false;

2. SQLite: Kho hàng khổng lồ

Khi dữ liệu của bạn phức tạp hơn, có mối quan hệ (như Bài viết có nhiều Comment), bạn cần một Database thực thụ. SQLite là một cơ sở dữ liệu quan hệ (RDBMS) nhỏ gọn nằm ngay trong điện thoại.

Cấu trúc bảng và quan hệ trong SQLite Mobile

Chúng ta thường dùng thư viện sqflite. Tuy code hơi dài dòng (phải viết câu lệnh SQL thủ công) nhưng nó cực kỳ mạnh mẽ.

// Tạo bảng
await db.execute(
  'CREATE TABLE dogs(id INTEGER PRIMARY KEY, name TEXT, age INTEGER)',
);

// Thêm dữ liệu
await db.insert(
  'dogs',
  {'id': 1, 'name': 'Milu', 'age': 2},
  conflictAlgorithm: ConflictAlgorithm.replace,
);

3. Bảng so sánh chiến lược

Khi nào dùng súng lục, khi nào dùng đại bác? Bảng dưới đây sẽ giúp bạn quyết định nhanh.

So sánh SharedPreferences vs SQLite: Tính năng và Hiệu năng

Lời khuyên:
– Nếu chỉ lưu Cài đặt, Token: Dùng SharedPreferences.
– Nếu lưu Danh sách Todo, Giỏ hàng offline: Dùng SQLite (hoặc Drift nếu lười viết SQL).
– Nếu cần Siêu tốc độ & đơn giản: Thử ngay Hive (NoSQL).


Dữ liệu đã có, nhưng làm sao hiển thị hình ảnh từ Camera hay cho người dùng chọn avatar từ thư viện ảnh? Khó đấy, nhưng Flutter làm nó trở nên dễ dàng.

Bài tiếp theo: Xử lý ảnh & media trong Flutter (Camera, Image Picker).

👉 Hướng dẫn chụp ảnh và chọn ảnh từ thư viện trong Flutter


💡 Bạn muốn học cách xây dựng Offline-First App, tự động đồng bộ khi có mạng?
Kiến trúc này được mổ xẻ chi tiết trong: Khóa học Lập trình Flutter Thực chiến

| Kết nối API REST trong Flutter thực chiến: Http, Dio & JSON Parsing

Được viết bởi thanhdt vào ngày 28/01/2026 lúc 07:27 | 46 lượt xem

Một ứng dụng mobile mà không có kết nối mạng thì chẳng khác nào một chiếc máy tính cầm tay 10 năm trước. Sức mạnh thực sự nằm ở việc lấy dữ liệu từ Server về điện thoại.

Trong Flutter, việc gọi API REST không khó, nhưng làm sao để chuyển đổi đống chữ JSON loằng ngoằng thành Object (Model) sịn sò để dùng trong Code thì lại là một nghệ thuật.

Thư viện Ưu điểm Nhược điểm
http Resmi của Google, nhẹ, dễ dùng Ít tính năng nâng cao (Interceptor, Cancel)
dio Mạnh mẽ, nhiều đồ chơi (Interceptor, Download file) Cồng kềnh hơn một chút

1. Vòng đời của một HTTP Request

Trước khi code, hãy hiểu luồng đi của dữ liệu:

  1. Request: App gửi một yêu cầu (GET/POST) kèm theo Header/Body lên địa chỉ Server.
  2. Processing: Server xử lý (truy vấn DB) và trả về kết quả.
  3. Response: Kết quả thường ở dạng chuỗi JSON.
  4. Parsing: App phải “dịch” chuỗi JSON đó thành class Dart để hiển thị.

2. JSON Parsing: Từ chuỗi vô tri thành Object có hồn

Đây là bước dễ sai nhất. Dart là ngôn ngữ định kiểu mạnh (Strongly Typed), nên bạn không thể cứ data['name'] bừa bãi như JavaScript được. Bạn cần tạo ra các Model Class.

Quy trình chuyển đổi JSON thành Dart Object

Ví dụ JSON trả về:

{ "id": 1, "name": "Thanh", "email": "thanh@gmail.com" }

Chúng ta tạo class Dart tương ứng:

class User {
  final int id;
  final String name;
  final String email;

  User({required this.id, required this.name, required this.email});

  // Hàm "thần thánh" để biến Map thành Object
  factory User.fromJson(Map<String, dynamic> json) {
    return User(
      id: json['id'],
      name: json['name'],
      email: json['email'],
    );
  }
}

3. Thực hành: Gọi API với thư viện http

Đầu tiên, thêm http vào pubspec.yaml. Sau đó viết hàm gọi API:

import 'package:http/http.dart' as http;
import 'dart:convert';

Future<List<User>> fetchUsers() async {
  final response = await http.get(Uri.parse('https://jsonplaceholder.typicode.com/users'));

  if (response.statusCode == 200) {
    // 1. Decode JSON string -> List<dynamic>
    List<dynamic> body = jsonDecode(response.body);

    // 2. Map từng item -> User Object
    List<User> users = body.map((item) => User.fromJson(item)).toList();

    return users;
  } else {
    throw Exception('Failed to load users');
  }
}

4. Xử lý lỗi (Error Handling) chuẩn chỉ

Đừng bao giờ tin tưởng mạng Internet. Nó có thể rớt bất cứ lúc nào. Vì vậy, luôn luôn phải bao bọc code gọi API trong khối try-catch.

Mô hình Safe API Call: Try/Catch Exceptions

Sử dụng FutureBuilder để hiển thị các trạng thái khác nhau lên UI:
ConnectionState.waiting: Hiện vòng xoay Loading.
snapshot.hasError: Hiện thông báo lỗi “Vui lòng kiểm tra mạng”.
snapshot.hasData: Hiện danh sách User.


Kết nối API xong rồi, nhưng nếu người dùng tắt mạng thì sao? Ứng dụng trắng xóa à? Không được!

Bài tiếp theo: Lưu trữ local trong Flutter: SharedPreferences & SQLite để App chạy Offline.

👉 Cách lưu dữ liệu vào bộ nhớ máy để dùng khi mất mạng


💡 Bạn muốn học cách cấu hình Dio Interceptor để tự động Refresh Token (JWT)?
Kỹ thuật nâng cao này được dạy kỹ trong: Khóa học Lập trình Flutter Thực chiến

| Navigation & Routing trong Flutter: Đi đâu và mang theo gì?

Được viết bởi thanhdt vào ngày 28/01/2026 lúc 07:25 | 57 lượt xem

Một ứng dụng di động hiếm khi chỉ có một màn hình. Việc chuyển đổi từ màn hình Danh sách sang Chi tiết, hay từ Giỏ hàng sang Thanh toán được gọi là Navigation.

Trong Flutter, Navigation không chỉ đơn giản là pushpop. Nó là cả một nghệ thuật về quản lý ngăn xếp (Stack) và điều hướng theo URL (Deep Link).

Phương pháp Độ khó Đặc điểm Khi nào dùng?
Navigator 1.0 Dễ Mệnh lệnh (Imperative) App đơn giản, ít màn hình
Navigator 2.0 Khó Khai báo (Declarative) App phức tạp, cần Deep Link
GoRouter Dễ Wrapper của Nav 2.0 Chuẩn mới của cộng đồng

1. Cơ chế Stack: Vào trước, Ra sau (LIFO)

Nền tảng của Navigation trong Flutter là Stack. Hãy tưởng tượng nó giống như một chồng đĩa.

  • Push: Đặt một màn hình mới lên đỉnh ngăn xếp (người dùng nhìn thấy màn hình này).
  • Pop: Gỡ bỏ màn hình trên cùng, quay lại màn hình cũ.
// Chuyển sang màn hình mới
Navigator.push(context, MaterialPageRoute(builder: (context) => DetailsPage()));

// Quay lại màn hình cũ
Navigator.pop(context);

2. Truyền dữ liệu giữa các màn hình

Khi chuyển màn hình, bạn thường muốn mang theo “hành lý” (ví dụ: ID sản phẩm, tên User).

Luồng truyền tham số (Arguments) giữa Screen A và Screen B

Cách 1: Truyền qua Constructor (Dễ nhất)

class DetailsPage extends StatelessWidget {
  final int id;
  // Nhận dữ liệu
  const DetailsPage({required this.id}); 
}

// Gửi dữ liệu
Navigator.push(context, 
  MaterialPageRoute(builder: (context) => DetailsPage(id: 42))
);

Cách 2: Truyền qua Arguments (Dùng cho Named Route)

Navigator.pushNamed(context, '/details', arguments: {'id': 42});

3. Navigator 2.0 (Router): Tại sao lại khó?

Navigator 1.0 rất tuyệt, nhưng nó gặp vấn đề lớn với Web (URL Bar) và Deep Linking. Navigator 2.0 ra đời để giải quyết việc này bằng cách đồng bộ hóa trạng thái App với URL.

Kiến trúc Navigator 2.0: URL -> Router -> Pages

Thay vì gọi push, bạn thay đổi một biến trạng thái (ví dụ selectedBook), và Router sẽ tự động quyết định xem nên hiển thị màn hình nào. Tuy nhiên, API của nó rất phức tạp.

Lời khuyên: Đừng dùng Navigator 2.0 thuần. Hãy dùng package go_router. Nó đơn giản hóa mọi thứ:

// Định nghĩa router
final router = GoRouter(
  routes: [
    GoRoute(path: '/', builder: (context, state) => HomePage()),
    GoRoute(path: '/details/:id', builder: (context, state) => DetailsPage(id: state.params['id'])),
  ],
);

// Sử dụng
context.go('/details/42');

Điều hướng đã xong. Bây giờ là lúc kết nối ứng dụng với thế giới bên ngoài. Làm sao để lấy dữ liệu từ Server về?

Bài tiếp theo: Kết nối API REST trong Flutter thực chiến (Http & Dio).

👉 Hướng dẫn gọi API và xử lý JSON trong Flutter


💡 Bạn muốn xây dựng App Thương mại điện tử với chức năng Giỏ hàng, Deep Link chuyên nghiệp?
Tất cả có trong dự án capstone của: Khóa học Lập trình Flutter Thực chiến

| State Management trong Flutter: Provider, Riverpod hay Bloc?

Được viết bởi thanhdt vào ngày 28/01/2026 lúc 07:21 | 48 lượt xem

Khi ứng dụng Flutter của bạn lớn dần lên, việc truyền dữ liệu từ widget cha xuống widget con cháu chắt chút chít bằng Constructor sẽ trở thành cơn ác mộng. Đó là lúc bạn cần đến State Management.

Nhưng giữa ma trận các thư viện như Provider, Riverpod, Bloc, GetX… đâu là chân ái cho dự án của bạn? Bài viết này sẽ đặt chúng lên bàn cân.

Thư viện Độ khó Đặc điểm nổi bật Phù hợp với
Provider Dễ Đơn giản, chuẩn Google App vừa & nhỏ
Riverpod Trung bình Compile-safe, không phụ thuộc Widget Tree App mọi quy mô
Bloc Khó Luồng dữ liệu chặt chẽ, dễ test App Enterprise lớn

1. Bức tranh toàn cảnh State Management

Hãy tưởng tượng State Management giống như hệ thống điện nước trong nhà. Thay vì kéo dây điện lằng nhằng từ phòng khách sang phòng ngủ (truyền qua Constructor), chúng ta xây một trạm biến áp trung tâm và các phòng chỉ việc cắm vào ổ điện để lấy năng lượng.

2. Provider: “Người bạn quốc dân”

Provider là thư viện được Google khuyên dùng cho người mới bắt đầu. Nó hoạt động dựa trên cơ chế InheritedWidget nhưng dễ dùng hơn nhiều.

Mô hình Provider: ChangeNotifier -> Consumer

Cách dùng:

  1. Tạo class Counter kế thừa ChangeNotifier.
  2. Bao bọc app bằng ChangeNotifierProvider.
  3. Dùng Consumer<Counter> hoặc context.watch<Counter>() để lắng nghe thay đổi.
class Counter extends ChangeNotifier {
  int count = 0;
  void increment() {
    count++;
    notifyListeners(); // Báo cho UI biết để vẽ lại
  }
}

3. Bloc: “Cỗ xe tăng” cho Enterprise

Bloc (Business Logic Component) tách biệt hoàn toàn giao diện (UI) và logic (Business). Nó hoạt động dựa trên các luồng sự kiện (Stream).

Luồng hoạt động của Bloc: Event -> Bloc -> State

  • Input: UI gửi Event (ví dụ: User bấm nút Login).
  • Process: Bloc nhận Event, xử lý logic (gọi API).
  • Output: Bloc bắn ra State (ví dụ: Loading, Success, Error).

Tuy code dài dòng (boilerplate) nhưng Bloc cực kỳ dễ viết Unit Test và debug, vì mọi thứ đều đi theo một luồng một chiều kiểm soát được.

4. Lời khuyên xương máu

  • Mới học: Dùng Provider. Đừng cố đấm ăn xôi với Bloc ngay.
  • Dự án cá nhân / Start-up: Dùng Riverpod. Nó khắc phục mọi nhược điểm của Provider (không cần BuildContext, an toàn tuyệt đối).
  • Dự án Ngân hàng / Tập đoàn: Dùng Bloc. Sự chặt chẽ là ưu tiên hàng đầu.

Sau khi chọn được “vũ khí” quản lý dữ liệu, thử thách tiếp theo là làm sao để chuyển đổi giữa các màn hình và truyền dữ liệu qua lại một cách mượt mà.

Bài tiếp theo: Navigation & Routing trong Flutter: Đi đâu và mang theo gì?

👉 Làm chủ điều hướng màn hình trong Flutter


💡 Bạn muốn học Bloc Pattern bài bản để apply vào các công ty lớn?
Module Bloc chuyên sâu có trong: Khóa học Lập trình Flutter Thực chiến

| Widget trong Flutter: Bí quyết xây dựng UI mobile đẹp lung linh

Được viết bởi thanhdt vào ngày 28/01/2026 lúc 07:10 | 59 lượt xem

Nếu lập trình Android truyền thống giống như xếp gạch xây nhà, thì Flutter giống như chơi LEGO. Mỗi mảnh ghép LEGO đầy màu sắc đó được gọi là Widget.

Để tạo ra một giao diện đẹp, bạn chỉ cần nắm vững cách lắp ghép các Widget lại với nhau. Nhưng câu hỏi đặt ra là: “Khi nào dùng Stateless? Khi nào dùng Stateful? Làm sao để chia cột chia dòng cho chuẩn?”. Bài viết này sẽ giải mã tất tần tật.

Loại Widget Đặc điểm Khi nào dùng?
Stateless Tĩnh tại, bất biến Icon, Text, Logo (Không thay đổi trên màn hình)
Stateful Động, có trạng thái Checkbox, TextField, Slider (Thay đổi khi user tương tác)

1. Stateless vs Stateful: Cuộc chiến của sự “Bất biến”

Đây là khái niệm quan trọng nhất mà mọi Newbie cần khắc cốt ghi tâm.

  • StatelessWidget: Được khởi tạo một lần và KHÔNG bao giờ thay đổi lại. Ví dụ: Một dòng chữ “Hello”.
  • StatefulWidget: Có thể tự vẽ lại (rebuild) khi dữ liệu thay đổi. Ví dụ: Ứng dụng đếm số, mỗi lần nhấn nút thì số tăng lên 1 đơn vị.
// Stateless: Nhẹ, nhanh, đơn giản
class MyText extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return const Text('Tôi không bao giờ thay đổi');
  }
}

// Stateful: Cần hàm setState() để báo UI cập nhật
class Counter extends StatefulWidget {
  @override
  _CounterState createState() => _CounterState();
}

2. Bộ tứ “Layout” quyền lực

Để sắp xếp các widget lên màn hình, bạn nhất định phải thuộc lòng “Bộ tứ siêu đẳng” này:

Cheat Sheet Layout Widget: Row, Column, Stack, Container

  1. Row (Hàng ngang): Sắp xếp widget từ trái sang phải. mainAxisAlignment chỉnh căn lề ngang.
  2. Column (Hàng dọc): Sắp xếp từ trên xuống dưới. Đây là widget dùng nhiều nhất.
  3. Stack (Chồng lớp): Đặt widget này đè lên widget kia. Dùng để làm background ảnh hoặc badge thông báo.
  4. Container (Cái hộp): Giống như <div> trong HTML, dùng để chỉnh margin, padding, màu nền, bo góc.

3. Thực hành: Mổ xẻ ứng dụng Counter

Hãy nhìn lại ứng dụng mẫu Counter mặc định của Flutter, nó chính là ví dụ hoàn hảo về sự kết hợp Layout và State.

Giao diện Counter App: Center text và Floating Action Button

  • Scaffold: Là khung xương của app (chứa AppBar, Body).
  • Center: Căn giữa widget con.
  • Column: Xếp dòng chữ “You have pushed…” và con số “0” thẳng hàng dọc.
  • FloatingActionButton: Nút bấm tròn ở góc dưới.

4. Mẹo tối ưu Widget Tree

  • Ưu tiên dùng const: Nếu widget không đổi, hãy thêm từ khóa const để Flutter không phải vẽ lại nó, giúp app mượt hơn.
  • Chia nhỏ Widget: Đừng viết một mạch 500 dòng code trong 1 file. Hãy tách nhỏ thành các Widget con riêng biệt để dễ quản lý (Component).

Nắm vững Widget là bạn đã nắm được 50% sức mạnh của Flutter. 50% còn lại nằm ở việc “Quản lý dữ liệu” chảy bên trong các Widget đó.

Bài tiếp theo: State Management trong Flutter (Provider, Riverpod, Bloc) – Chọn cái nào?

👉 So sánh các phương pháp quản lý State hiệu quả nhất


💡 Bạn muốn tự tay thiết kế những giao diện App đẹp như Dribbble?
Học tư duy UI/UX Mobile tại: Khóa học Lập trình Flutter Thực chiến

| Cài đặt môi trường Flutter & Tạo app mobile đầu tiên (Windows/Mac)

Được viết bởi thanhdt vào ngày 28/01/2026 lúc 07:07 | 73 lượt xem

Bạn đã sẵn sàng để dấn thân vào con đường trở thành Mobile Developer triệu đô chưa? Hành trình vạn dặm bắt đầu bằng một bước chân, và với Flutter, bước chân đó chính là Cài Đặt Môi Trường.

Rất nhiều bạn bỏ cuộc ngay từ bước này vì gặp lỗi biến môi trường (PATH) hay xung đột Android SDK. Đừng lo, bài viết này sẽ “cầm tay chỉ việc” giúp bạn thiết lập một môi trường code chuẩn chỉnh, ít lỗi vặt nhất.

Thành phần bắt buộc Windows macOS
Flutter SDK Tải zip & giải nén Tải zip & giải nén
Editor VS Code (nhẹ) VS Code (nhẹ)
PATH Variable Cần cập nhật thủ công Cần cập nhật thủ công
Emulator Android Studio Xcode (iOS) & Android Studio

1. Quy trình cài đặt chuẩn (Flowchart)

Trước khi bắt đầu, hãy nhìn qua sơ đồ tổng quan để biết chúng ta đang ở đâu:

  1. Tải Flutter SDK: Vào trang chủ flutter.dev, chọn hệ điều hành của bạn.
  2. Cập nhật PATH: Đây là bước quan trọng nhất. Bạn cần thêm đường dẫn flutter/bin vào biến môi trường của máy tính để có thể gõ lệnh flutter ở bất cứ đâu.
  3. Flutter Doctor: Chạy lệnh flutter doctor trong terminal. Nó giống như một bác sĩ khám bệnh, sẽ báo cho bạn biết máy bạn thiếu cái gì (thiếu Android SDK, chưa cài VS Code, v.v…).

2. Giải mã cấu trúc Project Flutter

Sau khi cài đặt xong, hãy tạo dự án đầu tiên bằng lệnh:

flutter create my_first_app

Mở VS Code lên, bạn sẽ thấy một rừng thư mục. Đừng hoảng! Bạn chỉ cần quan tâm những thư mục được đánh dấu này thôi:

Cấu trúc thư mục dự án Flutter trong VS Code

  • lib/: Đây là “nhà” của chúng ta. 99% thời gian bạn sẽ code ở đây. File main.dart chính là cửa ngõ chính của ứng dụng.
  • android/ & ios/: Chứa các file cấu hình riêng cho từng nền tảng (ví dụ xin quyền Camera, sửa icon app).
  • pubspec.yaml: File “thần thánh” để khai báo thư viện (giống package.json của Node.js). Muốn thêm gói xoay ảnh hay map? Khai báo vào đây.

3. Hello World – Ứng dụng đầu đời

Hãy mở file lib/main.dart, xóa sạch sành sanh mọi thứ và gõ lại đoạn code sau. Đừng copy paste, hãy gõ để cảm nhận!

Ứng dụng Flutter Hello World đầu tiên chạy trên máy ảo

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Ứng dụng đầu tay'),
          backgroundColor: Colors.blue,
        ),
        body: const Center(
          child: Text(
            'Hello World!',
            style: TextStyle(fontSize: 30, color: Colors.blue),
          ),
        ),
      ),
    );
  }
}

Nhấn F5 để chạy. Bùm! Bạn vừa chính thức trở thành một lập trình viên Flutter tập sự.

4. Các lỗi thường gặp khi cài đặt

  • “flutter command not found”: Bạn chưa thêm đường dẫn vào PATH. Hãy kiểm tra lại phần Environment Variables.
  • “Android License Status Unknown”: Bạn cần chạy lệnh flutter doctor --android-licenses và nhấn y liên tục để đồng ý.

Cài đặt môi trường tuy hơi khô khan nhưng là nền móng vững chắc. Ở bài tiếp theo, chúng ta sẽ bắt đầu “vọc vạch” sâu hơn vào các khối gạch tạo nên giao diện: Widget.

Bài tiếp theo: Widget trong Flutter: Bí quyết UI mobile đẹp (Stateless vs Stateful).

👉 Khám phá sức mạnh của Widget trong Flutter


💡 Bạn muốn bỏ qua việc mò mẫm lỗi setup và được hướng dẫn 1-1?
Tham gia ngay: Khóa học Lập trình Flutter Thực chiến (Kèm Setup tận răng)

| Flutter là gì? Hướng dẫn toàn tập cho người mới bắt đầu (2025)

Được viết bởi thanhdt vào ngày 28/01/2026 lúc 07:05 | 64 lượt xem

Bạn đang muốn xây dựng ứng dụng di động cho cả iOS và Android nhưng e ngại việc phải học hai ngôn ngữ lập trình khác nhau? Bạn nghe nói đến Flutter như một “vị thần” mới nổi trong làng công nghệ, nhưng chưa rõ nó hoạt động ra sao?

Bài viết này chính là tấm bản đồ (Pillar Article) giúp bạn đi từ con số 0 đến cái nhìn toàn cảnh về hệ sinh thái Flutter. Chúng ta sẽ cùng mổ xẻ kiến trúc, so sánh với React Native, và vạch ra lộ trình chinh phục công nghệ này.

Tiêu chí Flutter (Google) React Native (Facebook)
Ngôn ngữ Dart JavaScript
Kiến trúc Native Compilation (Skia) JS Bridge (Cầu nối)
Hiệu năng Rất cao (gần như Native) Khá (tùy thuộc Bridge)
UI Widget Đồng bộ trên mọi OS Phụ thuộc OS Native UI

1. Flutter hoạt động như thế nào?

Khác với các Framework Cross-platform đới cũ dựa vào WebView (như Ionic) hay JS Bridge (như React Native), Flutter chọn một lối đi riêng đầy táo bạo: Tự vẽ lại tất cả.

Flutter sử dụng Skia Graphics Engine (được viết bằng C++) để render từng pixel lên màn hình. Điều này có nghĩa là ứng dụng Flutter không phụ thuộc vào các UI component có sẵn của iOS hay Android.

Lợi ích “chết người” của cách tiếp cận này:

  • Giao diện đồng nhất: App của bạn sẽ trông y hệt nhau trên cả iPhone đời cũ và Samsung đời mới (trừ khi bạn muốn khác).
  • Hiệu năng 60fps: Không còn độ trễ khi qua cầu nối (Bridge), mọi thứ được biên dịch thẳng ra mã máy (Machine Code).

2. Widget: Trái tim của Flutter

Trong thế giới Flutter, câu cửa miệng là: “Everything is a Widget” (Mọi thứ đều là Widget). Từ một nút bấm (Button), một khoảng trắng (Padding), cho đến cả bố cục màn hình (Scaffold) – tất cả đều là Widget.

Chúng được tổ chức theo cấu trúc cây (Tree Structure):

Cấu trúc Widget Tree trong Flutter: Root -> Child

// Ví dụ Hello World đơn giản nhất
import 'package:flutter/material.dart';

void main() => runApp(
  MaterialApp(
    home: Scaffold(
      appBar: AppBar(title: Text('Hello Flutter')),
      body: Center(child: Text('Chào mừng bạn!')),
    ),
  )
);

3. Tại sao doanh nghiệp đổ xô dùng Flutter?

  • Hot Reload: Tính năng “thần thánh” giúp Dev nhìn thấy thay đổi giao diện ngay lập tức (< 1 giây) mà không cần build lại app. Vừa code vừa uống cafe mà vẫn nhanh!
  • Tiết kiệm 50% chi phí: Chỉ cần 1 team Dev, viết 1 source code, chạy được trên cả iOS, Android, Web, Windows, và MacOS.
  • Cộng đồng khổng lồ: Được Google “chống lưng”, số lượng package (thư viện) trên pub.dev đã vượt mốc 30,000.

4. Lộ trình học Flutter từ Zero đến Hero

Để làm chủ Flutter, bạn không nên học lan man. Hãy đi theo lộ trình chuẩn sau:

Lộ trình học Flutter chuyên nghiệp: Từ Dart đến Master

  1. Học ngôn ngữ Dart: Nắm chắc cú pháp, OOP, Asynchronous (Future/Stream).
  2. Làm quen Widget: Row, Column, Stack, ListView. Xem bài: Widget trong Flutter
  3. State Management: Bắt đầu với Provider, sau đó nâng cao lên Bloc hoặc Riverpod. Xem bài: State Management Flutter
  4. Networking: Kết nối API lấy dữ liệu. Xem bài: Kết nối API REST
  5. Database: Lưu trữ offline. Xem bài: Lưu trữ Local

Flutter không chỉ là một xu hướng nhất thời, nó là tương lai của lập trình đa nền tảng. Nếu bạn muốn bắt đầu ngay hôm nay, hãy chuẩn bị sẵn sàng công cụ “chiến đấu”.

Bài tiếp theo: Cài đặt môi trường Flutter & Tạo app mobile đầu tiên (Windows/Mac).

👉 Hướng dẫn cài đặt Flutter chi tiết chuẩn 2025


💡 Bạn muốn một lộ trình học bài bản, có mentor hướng dẫn trực tiếp làm dự án thực tế?
Tham khảo ngay: Khóa học Lập trình Flutter Thực chiến từ A-Z