Phỏng vấn vị trí lập trình viên Mobile Flutter (Android & iOS)


Chào bạn, dưới đây là bộ 50 câu hỏi phỏng vấn Flutter từ cơ bản đến nâng cao, bao gồm giải thích chi tiết và code demo để bạn có thể ôn tập và chuẩn bị tốt nhất cho buổi phỏng vấn.


  • Giải thích: Flutter là một UI SDK của Google để xây dựng ứng dụng biên dịch nguyên bản (native) cho di động, web và desktop từ một codebase duy nhất. Dart được chọn vì hỗ trợ cả JIT (Just-in-Time) để hot reload nhanh và AOT (Ahead-of-Time) để tối ưu hiệu suất khi release.

  • Code Demo: Không yêu cầu code phức tạp, chỉ cần cấu trúc main:

Dart
void main() => runApp(MyApp());
  • Giải thích: StatelessWidget không thay đổi trạng thái sau khi được dựng. StatefulWidget có thể thay đổi dữ liệu bên trong và cập nhật lại giao diện thông qua hàm setState().

  • Code Demo:

Dart
class MyText extends StatelessWidget {
  @override
  Widget build(BuildContext context) => Text("I am Stateless");
}
  • Giải thích: Hot Reload đẩy các thay đổi code vào VM và cập nhật UI mà không mất State. Hot Restart khởi động lại toàn bộ app và làm mất State hiện tại.

  • Code Demo: (Cơ chế IDE)

  • Giải thích: - Widget Tree: Cấu trúc do cấu hình code.

    • Element Tree: Cầu nối giữa Widget và RenderObject, quản lý vòng đời.

    • RenderObject Tree: Trực tiếp vẽ giao diện lên màn hình.

  • Code Demo: (Cấu trúc hệ thống)

  • Giải thích: Gồm các bước: createState -> initState -> didChangeDependencies -> build -> didUpdateWidget -> deactivate -> dispose.

  • Code Demo:

Dart
@override
void initState() {
  super.initState();
  print("Khởi tạo dữ liệu");
}
  • Giải thích: Context là một locator xác định vị trí của Widget trong Element Tree. Nó giúp truy cập các widget cha (như Theme, MediaQuery).

  • Code Demo:

Dart
Theme.of(context).primaryColor;
  • Giải thích: main() là điểm bắt đầu của chương trình Dart. runApp() là hàm khởi chạy framework Flutter và gắn Widget gốc vào màn hình.

  • Code Demo:

Dart
void main() {
  runApp(MaterialApp(home: Text("Hello")));
}
  • Giải thích: Giúp Widget tránh các vùng "tai thỏ", thanh trạng thái hoặc các phần bị che khuất bởi phần cứng.

  • Code Demo:

Dart
SafeArea(child: Text("Nội dung an toàn"));
  • Giải thích: Cả hai đều dùng trong Row/Column. Expanded bắt buộc chiếm hết không gian trống, Flexible có thể thu nhỏ lại nếu nội dung bên trong nhỏ hơn.

  • Code Demo:

Dart
Row(children: [
  Expanded(child: Container(color: Colors.red)),
  Flexible(child: Container(color: Colors.blue)),
]);
  • Giải thích: SizedBox dùng để cố định kích thước (nhẹ hơn). Container hỗ trợ thêm decoration, padding, margin, transform (nặng hơn).

  • Code Demo:

Dart
SizedBox(width: 20); // Tạo khoảng trống
Container(decoration: BoxDecoration(color: Colors.red));
  • Giải thích: Gồm Navigator 1.0 (Imperative - Push/Pop) và Navigator 2.0 (Declarative - Router API).

  • Code Demo:

Dart
Navigator.push(context, MaterialPageRoute(builder: (_) => DetailScreen()));
  • Giải thích: Giúp Flutter tái sử dụng Widget đó thay vì khởi tạo lại, từ đó tối ưu hiệu suất rebuild.

  • Code Demo:

Dart
const Text("Dữ liệu tĩnh");
  • Giải thích: Giúp Flutter giữ đúng State khi các Widget cùng loại thay đổi vị trí trong Widget Tree (thường dùng trong danh sách có thể sắp xếp).

  • Code Demo:

Dart
ListTile(key: ValueKey(item.id));
  • Giải thích: Future là kết quả trả về trong tương lai. async đánh dấu hàm bất đồng bộ, await dừng việc thực hiện cho đến khi Future hoàn tất.

  • Code Demo:

Dart
Future<void> fetchData() async {
  var data = await api.get();
}
  • Giải thích: Future trả về 1 giá trị duy nhất rồi kết thúc. Stream là một dòng dữ liệu trả về liên tục nhiều giá trị theo thời gian.

  • Code Demo:

Dart
Stream<int> counter() async* {
  yield 1; yield 2;
}
  • Giải thích: Là một thư viện quản lý trạng thái (State Management) dựa trên InheritedWidget, giúp truyền dữ liệu từ cha xuống con dễ dàng.

  • Code Demo:

Dart
Provider.of<MyModel>(context).doSomething();
  • Giải thích: Tách biệt Logic và UI bằng cách sử dụng Stream/Sink. UI gửi sự kiện (Event), BLoC xử lý và trả về trạng thái (State).

  • Code Demo: (Cần thư viện flutter_bloc)

Dart
context.read<CounterBloc>().add(Increment());
  • Giải thích: Là cách tái sử dụng code của một class trong nhiều hierarchy khác nhau mà không cần kế thừa (Inheritance). Dùng từ khóa with.

  • Code Demo:

Dart
mixin Logger { void log(String msg) => print(msg); }
class MyController with Logger {}
  • Giải thích: double.infinity yêu cầu Widget chiếm toàn bộ không gian mà cha nó cho phép. MediaQuery lấy chính xác kích thước vật lý của màn hình.

  • Giải thích: EphemeralState là state cục bộ trong 1 widget (như index của PageView). AppState là state dùng chung cho toàn bộ app (như thông tin User).

  • Giải thích: Chủ yếu bằng C++, thực hiện các nhiệm vụ đồ họa thông qua thư viện Skia (hoặc Impeller mới).

  • Giải thích: Quản lý các dependency, phiên bản app, assets (hình ảnh, font) và các cấu hình môi trường.

  • Giải thích: Sử dụng MethodChannel.

  • Code Demo:

Dart
static const platform = MethodChannel('com.example/battery');
final int result = await platform.invokeMethod('getBatteryLevel');
  • Giải thích: - Debug: Hỗ trợ Hot Reload, chậm.

    • Profile: Kiểm tra hiệu suất.

    • Release: Tối ưu kích thước, tốc độ nhanh nhất.

  • Giải thích: Quá trình loại bỏ các code không được sử dụng khi đóng gói ứng dụng (thường thấy khi xử lý icon font).

  • Giải thích: Dùng để vẽ các hình dạng đồ họa phức tạp (đường thẳng, hình tròn, path) mà các widget cơ bản không đáp ứng được.

  • Giải thích: Column xếp chồng các widget theo chiều dọc (không đè lên nhau). Stack cho phép các widget nằm đè lên nhau.

  • Giải thích: Cả hai bắt sự kiện chạm. InkWell có hiệu ứng ripple (gợn sóng), GestureDetector thì không nhưng hỗ trợ nhiều cử chỉ hơn (kéo, thả, xoay).

  • Giải thích: Dùng try-catch hoặc .catchError().

  • Code Demo:

Dart
fetchData().catchError((e) => print(e));
  • Giải thích: Const là hằng số lúc biên dịch (compile-time). Final là hằng số lúc chạy (runtime) - chỉ gán giá trị được một lần.

  • Giải thích: Thường dùng package http hoặc dio.

  • Code Demo:

Dart
var response = await http.get(Uri.parse('url'));
  • Giải thích: FutureBuilder lắng nghe 1 Future duy nhất. StreamBuilder lắng nghe 1 Stream và cập nhật UI mỗi khi có dữ liệu mới đổ về.

  • Giải thích: Set debugShowCheckedModeBanner: false trong MaterialApp.

  • Giải thích: Cố định tỷ lệ khung hình (ví dụ 16:9) cho widget con bên trong.

  • Giải thích: ElevatedButton, OutlinedButton, TextButton, IconButton.

  • Giải thích: Là lớp cơ sở cho phép truyền dữ liệu xuống sâu trong cây Widget mà không cần truyền qua constructor của từng lớp trung gian.

  • Giải thích: Chỉ khởi tạo những item đang hiển thị trên màn hình, giúp tiết kiệm bộ nhớ cho danh sách dài.

  • Giải thích: Dùng shared_preferences (key-value đơn giản) hoặc sqflite (database), Hive (NoSQL).

  • Giải thích: Dùng để chạy một task sau khi frame hiện tại đã được vẽ xong (thường dùng để hiển thị Dialog ngay sau khi vào màn hình).

  • Code Demo:

Dart
SchedulerBinding.instance.addPostFrameCallback((_) => showMyDialog());
  • Giải thích: - Opacity: Làm mờ nhưng vẫn chiếm chỗ.

    • Visibility: Có thể ẩn hoàn toàn và không chiếm chỗ.

    • Offstage: Vẫn tồn tại nhưng không được vẽ và không chiếm chỗ.

  • Giải thích: Ngăn chặn lỗi "null pointer exception" bằng cách phân biệt rõ kiểu dữ liệu có thể null (int?) và không thể null (int).

  • Giải thích: Khai báo một biến sẽ được khởi tạo sau nhưng đảm bảo nó không null khi sử dụng.

  • Giải thích: Cho phép thêm chức năng mới vào các class có sẵn mà không cần kế thừa.

  • Code Demo:

Dart
extension StringExt on String {
  bool get isEmail => contains('@');
}
  • Giải thích: Dart chạy đơn luồng (Single-thread). Isolates là cách chạy các tác vụ nặng trên một luồng riêng biệt để không làm lag UI.

  • Giải thích: Nhờ Engine Skia tự vẽ mọi pixel, không qua cầu nối (bridge) trung gian như React Native.

  • Giải thích: Buộc ListView chỉ chiếm không gian vừa đủ với các item bên trong, thay vì cố gắng chiếm toàn bộ không gian của cha.

  • Giải thích: Truy cập trực tiếp vào State của một widget khác hoặc giữ State khi widget di chuyển giữa các cha khác nhau.

  • Giải thích: Sử dụng SystemChrome.setPreferredOrientations.

  • Giải thích: Cấu hình các môi trường khác nhau (Dev, Staging, Prod) với các bundle ID và cấu hình API khác nhau.

  • Giải thích: List là danh sách có thứ tự. Map là tập hợp các cặp key-value (mỗi key là duy nhất).

Phản hồi từ học viên

5

Tổng 0 đánh giá
Developer Toolbox

TEXT CASE

FORMAT & CLEAN

ENCODE & DECODE

JSON & CRYPTO

Đã sao chép!!!
Gozic - Hệ thống học lập trình, luyện thi, kiểm tra trắc nghiệm trực tuyến uy tín tại Việt Nam.
Hotline: 0967025996
Gozic - Hệ thống học lập trình, luyện thi, kiểm tra trắc nghiệm trực tuyến uy tín tại Việt Nam.