Tổng hợp 74 câu hỏi phỏng vấn Mobile Essentials kèm đáp án chi tiết, song ngữ Việt–Anh — sắp xếp từ cơ bản đến nâng cao. Ôn luyện miễn phí, tự động lưu tiến độ.
Future là một giá trị sẽ có một lần trong tương lai (giống Promise của JS); Stream là chuỗi nhiều giá trị đến dần theo thời gian, như một băng chuyền. Trong Flutter, FutureBuilder dựng UI từ một Future, StreamBuilder dựng UI từ một Stream.…
StatelessWidget chỉ phụ thuộc vào tham số truyền vào (và các InheritedWidget nó đọc); StatefulWidget có thêm một object State sống lâu, giữ dữ liệu thay đổi được trong lúc widget còn trên cây. - StatelessWidget: build() chạy lại khi widget cha rebuild với tham…
BuildContext là "địa chỉ" của widget trong cây — thực chất nó chính là Element của widget đó. Mọi thao tác "tìm ngược lên cây" đều đi qua context: Theme.of(context), MediaQuery.of(context), Navigator.of(context), ScaffoldMessenger.of(context). Vì of(context) tìm từ vị trí của context đi lên, dùng context…
Flutter tách UI thành ba cây với vai trò khác nhau: widget là bản mô tả, element là "phiên bản đang sống" giữ vị trí và state, render object lo layout và vẽ. - Widget tree: object bất biến, rẻ, được tạo lại mỗi lần…
Key giúp Flutter nhận ra "đây vẫn là widget cũ" khi vị trí của nó trong danh sách con thay đổi. Element so widget mới với cũ bằng Widget.canUpdate: cùng runtimeType và cùng key. Không có key, Flutter chỉ so theo kiểu + vị trí.…
const constructor tạo object ngay lúc compile, và hai biểu thức const giống hệt nhau trả về cùng một instance (canonicalization). Lợi ích trong Flutter đến từ chính điều đó: khi widget cha rebuild, element so widget mới với widget cũ. Nếu widget con là…
setState() báo cho framework biết state trong State vừa đổi: nó chạy callback đồng bộ, rồi đánh dấu element là dirty (markNeedsBuild). Flutter gọi lại build() ở frame kế tiếp chứ không rebuild ngay, và nhiều lần setState trong cùng frame chỉ gây một lần…
BLoC (Business Logic Component) tách logic khỏi UI theo một chiều: UI gửi event vào, BLoC xử lý rồi phát ra state mới, UI chỉ vẽ theo state. Bộ package thường dùng là bloc + flutterbloc. Phía UI: BlocProvider cung cấp bloc xuống cây, BlocBuilder…
Ba lựa chọn phổ biến nhất, khác nhau chủ yếu ở mức ràng buộc kiến trúc: Provider Riverpod BLoC / Cubit ------------ Bản chất Wrapper quanh InheritedWidget + ChangeNotifier Viết lại từ Provider, không phụ thuộc BuildContext Luồng event → state trên Stream Lỗi thiếu…
Navigator 1.0 là API imperative: bạn tự push/pop từng màn lên stack. Navigator 2.0 (Router API) là declarative: stack màn hình được suy ra từ state của app, thường là URL. gorouter là package của Flutter team bọc Router API cho dễ dùng, và là…
Clean architecture tách code thành các layer: Presentation (UI, widget), Domain (logic nghiệp vụ, entity, use case), Data (repository, data source). Mỗi layer độc lập và có thể test. Sự tách biệt này cho phép thay đổi UI framework, thay data source, và test logic…
Suspend function là hàm có thể tạm dừng mà không chặn thread, rồi chạy tiếp khi có kết quả. Nó chỉ gọi được từ một coroutine hoặc từ một suspend function khác. Cơ chế: compiler biến hàm suspend thành hàm nhận thêm một tham số…
Activity lifecycle là chuỗi callback hệ thống gọi khi một màn hình được tạo, hiện ra, mất focus, bị che và bị huỷ: - onCreate(): khởi tạo một lần — setContent/setContentView, lấy ViewModel, đọc savedInstanceState. - onStart(): Activity hiện ra (visible). - onResume(): ở foreground…
Intent là object "yêu cầu" gửi cho hệ thống để khởi động một component: mở Activity, chạy Service, gửi broadcast. Có hai loại: - Explicit intent: chỉ rõ component đích — thường dùng trong nội bộ app. - Implicit intent: chỉ khai báo hành động…
Service là component chạy việc không cần UI. Nó chạy trên main thread của process, nên việc nặng vẫn phải tự đẩy sang coroutine hoặc thread khác. Ba dạng: - Started service (startService): chạy đến khi tự stopSelf() hoặc bị dừng. - Foreground service: bắt…
Android chia permission theo mức rủi ro: - Normal (INTERNET, VIBRATE): khai báo trong manifest là được cấp khi cài. - Dangerous / runtime (camera, vị trí, danh bạ, micro, POSTNOTIFICATIONS từ Android 13): từ Android 6.0 (API 23) phải xin lúc chạy; người dùng…
mutableStateOf() tạo một MutableState<T mà Compose theo dõi được: composable nào đọc .value sẽ được recompose khi giá trị đổi. remember giữ object đó qua các lần recomposition — thiếu remember, mỗi lần recompose lại tạo state mới về giá trị ban đầu. Các biến…
MVVM (Model-View-ViewModel) tách UI logic khỏi business logic: Model chứa dữ liệu và business rule, View hiển thị UI (Activity/Fragment/Composable), ViewModel chứa UI state và logic, tồn tại qua configuration change. ViewModel expose LiveData/StateFlow để View observe. Sự tách biệt này cải thiện khả năng…
Cả hai đều giữ giá trị hiện tại và báo cho observer khi giá trị đổi, nhưng khác gốc: LiveData là class của Android, lifecycle-aware sẵn; StateFlow thuộc Kotlin coroutines, không phụ thuộc Android. LiveData StateFlow --------- Giá trị ban đầu Không bắt buộc (có…
ViewModel là state holder của một màn hình: giữ và chuẩn bị dữ liệu cho UI, và sống qua configuration change (xoay màn hình, đổi dark mode) — Activity bị tạo lại nhưng ViewModel vẫn còn, không phải gọi API lại. Vai trò đúng theo…
Room là thư viện Jetpack bọc SQLite: bạn khai báo entity và câu query bằng annotation, Room sinh code lúc compile (qua KSP) và kiểm tra câu SQL ngay lúc build. So với dùng SQLiteOpenHelper trực tiếp: - Sai tên cột hay cú pháp SQL…
Interceptor chặn HTTP request/response để chỉnh sửa chúng. - Application interceptor chạy một lần cho mỗi request; network interceptor chạy cho từng lần gọi network thực tế (kể cả redirect và retry). - Dùng phổ biến: gắn auth header, log request/response, xử lý refresh token,…
Hermes là JavaScript engine open-source do Meta viết riêng cho React Native, tối ưu cho thời gian khởi động, bộ nhớ và kích thước app. JSC (JavaScriptCore) là engine của Safari, từng là mặc định của RN. Khác biệt chính: - Biên dịch bytecode trước…
RN tính layout bằng Yoga (engine C++ của Meta). Flexbox chạy gần giống web nhưng giá trị mặc định khác — đây là chỗ dev web hay vấp: React Native Web CSS --------- flexDirection column row flexShrink 0 1 alignContent flex-start stretch flex chỉ nhận…
Stack Navigator: điều hướng kiểu push/pop — màn hình mới đè lên màn cũ. Có hai bản: @react-navigation/native-stack dùng UINavigationController (iOS) và Fragment (Android) nên animation, gesture do platform xử lý — nên chọn mặc định; @react-navigation/stack viết bằng JS, tuỳ biến animation được nhiều…
FlatList virtualize: chỉ mount items hiện đang trong "window" (vùng nhìn thấy + buffer hai phía), unmount items ngoài window khi scroll. Memory ổn định không phụ thuộc tổng số item. Tham số quan trọng: - windowSize (default 21): số "screenful" được render. 21 nghĩa…
Quy tắc giống React web: memo hoá chỉ có ích khi cần giữ reference ổn định cho thứ đang so sánh reference (React.memo, dependency array, props của FlatList). Khác biệt là trên máy Android cấu hình thấp, render thừa trong list dài dễ thành giật…
New Architecture là tên gọi chung cho 3 phần Meta viết lại RN từ năm 2020: 1. JSI (JavaScript Interface): C++ layer thay Bridge cũ. JS engine có tham chiếu trực tiếp tới object C++/native — gọi sync, không serialize JSON. 2. TurboModules: thay native…
Animated API (built-in RN core): - Driver useNativeDriver: true đẩy animation lên native thread, smooth. - Hạn chế: native driver chỉ animate được thuộc tính không ảnh hưởng layout (opacity, transform); animate width/height/top phải useNativeDriver: false → chạy trên JS thread, dễ jank. - API…
Hai dịch vụ native cần biết: - APNs (Apple Push Notification service): iOS push. - FCM (Firebase Cloud Messaging): Android push, có thể proxy iOS qua APNs. Option 1 — Direct (@react-native-firebase/messaging + APNs): - Setup phức tạp: cần Firebase project, push cert/auth key APNs,…
- Hot reload: nạp mã Dart đã sửa vào máy ảo đang chạy rồi dựng lại cây widget, giữ nguyên state của app. Rất nhanh (thường dưới 1s), hợp chỉnh UI. Không chạy lại main(). - Hot restart: khởi động lại app, dựng lại toàn…
Chọn theo loại dữ liệu: - sharedpreferences: cặp key–value đơn giản (cờ, cấu hình, lựa chọn của người dùng). Không hợp dữ liệu lớn/có cấu trúc. - File: đọc/ghi file trong thư mục app cho blob/tài liệu. - SQLite (sqflite): CSDL quan hệ cho dữ…
Fragment là thành phần UI tái sử dụng có vòng đời riêng, sống bên trong Activity (hoặc Fragment khác) — dùng để chia UI thành phần nhỏ và hỗ trợ layout đa kích thước (điện thoại/tablet). Khác biệt chính: - Fragment có thêm các callback…
Compose là UI khai báo: bạn viết các hàm @Composable nhận dữ liệu (state) và sinh ra UI tương ứng. Khi state đọc bên trong đổi, Compose chạy lại các composable liên quan để cập nhật UI — đó là recomposition. Điểm quan trọng: -…
Navigation Component chuẩn hoá việc điều hướng trong app thành một đồ thị (navigation graph) khai báo, thay cho việc tự quản FragmentTransaction/intent rải rác. Khái niệm chính: - NavGraph: tập các đích (destination) và các đường đi giữa chúng. - NavHost: vùng chứa hiển…
RN dùng cùng React hooks như React web (hooks không gắn với DOM). - useState: khai báo state trong function component; gọi setter làm component render lại. - useEffect: chạy side-effect (gọi API, đăng ký listener, timer) sau khi render. Mảng dependency quyết định khi…
RN chạy hai luồng chính, mỗi luồng đều cần đạt ~60fps (16ms/frame): - JS thread: chạy logic React, xử lý sự kiện, quyết định UI. Nếu bận (tính toán nặng, render list lớn, quá nhiều console.log), JS không kịp trả frame → giật khi cuộn/tương…
Khác với vòng đời từng màn, app mobile còn có trạng thái toàn app do OS quản: đang mở (foreground), chạy nền (background), hoặc bị hệ thống thu hồi (killed). Vì sao quan trọng: - Vào background nên dừng camera/animation/timer, lưu state, ngắt kết nối…
Mạng mobile chập chờn và tốn pin, nên tầng networking cần chắc chắn: - Gọi API: dùng fetch/axios (RN), Retrofit (Android), Dio (Flutter). Đặt timeout, huỷ request khi rời màn, xử lý lỗi và trạng thái loading rõ ràng. - Retry có kiểm soát: thử…
Deep link là URL mở app tới đúng một màn/nội dung cụ thể (ví dụ link quảng cáo mở thẳng trang sản phẩm), thay vì chỉ mở màn chính. Các loại: - Custom URL scheme (myapp://product/12): đơn giản, chạy mọi phiên bản, nhưng không xác…
Trước khi lên store, app phải được ký số (code signing) bằng chứng chỉ — đây là cách nền tảng xác thực nguồn gốc và toàn vẹn của bản cài. Vì sao cần: - Đảm bảo app đến từ đúng nhà phát triển và không…
Cả hai giúp app dùng tốt trên nhiều kích thước (điện thoại, tablet, gập, desktop) nhưng khác trọng tâm: - Responsive: điều chỉnh cách sắp xếp UI cho vừa không gian có sẵn — co giãn, đổi số cột, xuống dòng. Ví dụ: 1 cột…
Thiết bị có thể bị mất, root/jailbreak, hoặc app bị dịch ngược → không được coi client là môi trường tin cậy. Lưu trữ nhạy cảm: - Token/mật khẩu/khoá để trong kho an toàn của OS: Android Keystore, iOS Keychain. Thư viện EncryptedSharedPreferences đã bị…
Cả hai đều dùng để khởi tạo muộn một property non-null, nhưng ai khởi tạo và khi nào thì khác nhau: lateinit var val ... by lazy { } --------- Kiểu biến var (gán lại được) val (chỉ đọc) Ai gán giá trị Code bên…
Khác nhau ở chỗ UI được vẽ bằng gì và code chạy trên nền nào: - Native: viết riêng cho từng nền tảng — Kotlin/Java cho Android, Swift cho iOS. Truy cập đầy đủ API hệ thống, hiệu năng tốt nhất, nhưng phải duy trì…
- versionCode: số nguyên nội bộ, người dùng không thấy. Google Play và hệ điều hành dùng nó để biết bản nào mới hơn: mỗi lần upload phải lớn hơn bản trước, và Android chặn cài bản có versionCode thấp hơn bản đang có (chống…
Flavor là các biến thể build của cùng một codebase cho từng môi trường — thường là dev, staging, production. Mỗi flavor có thể có tên app, icon, API endpoint, feature flag và application ID riêng (bên Android gọi là product flavor, kết hợp với…
Nguyên nhân: khi app vào background, hệ điều hành tạm dừng hoặc giới hạn JS thread, nên setInterval ngừng chạy. Nếu mỗi giây trừ remaining - 1, quay lại app sẽ thấy đồng hồ đứng yên hoặc lệch. Cách đúng: lưu mốc thời gian kết…
Không thể ngồi cạnh từng người dùng, nên app cần một crash reporting SDK (Firebase Crashlytics, Sentry) gom crash về một dashboard: nhóm theo stack trace, đếm số người dùng bị ảnh hưởng, lọc theo phiên bản app/OS/thiết bị. Trong Flutter phải bắt hai nguồn…
Khi thiếu RAM, hệ điều hành kill process của app đang nằm nền (process death). Khác với người dùng tự tắt app, lúc quay lại Android dựng lại đúng màn hình cũ (iOS vẫn hiện snapshot màn hình cũ trong app switcher) nên người dùng…
Hai store có luồng giống nhau: build có chữ ký → phát cho tester → review → phát hành dần. Google Play: 1. Build App Bundle (AAB) đã ký, versionCode tăng so với bản trước. 2. Upload lên các track test: internal (tối đa 100…
Sinh trắc học không thay thế đăng nhập với server — nó chỉ mở khoá một thứ đã lưu sẵn trên máy (thường là refresh token) hoặc xác nhận một thao tác (chuyển tiền). Cách yếu: gọi prompt, nhận true/false rồi cho vào app. Kết…
WebView hợp với nội dung thay đổi thường xuyên hoặc đã có sẵn trên web: trang điều khoản, chương trình khuyến mãi, mini app của đối tác, trang cổng thanh toán. Đổi nội dung không cần phát hành bản app mới. Đổi lại: tốn bộ…
Nguyên nhân thường gặp: ảnh được giải mã ở kích thước gốc. Ảnh trong bộ nhớ ở dạng chưa nén, khoảng width × height × 4 byte — ảnh 4K (3840×2160) chiếm hơn 30 MB RAM dù chỉ hiển thị thành thumbnail 120×120. Vài chục…
Context là cầu nối tới tài nguyên và dịch vụ hệ thống: truy cập resources, khởi động Activity/Service, lấy getSystemService(), mở database... Về vòng đời có hai loại chính: - Activity context: gắn với vòng đời một Activity, biết về theme/UI. Dùng khi cần theme…
ANR là hộp thoại hệ thống hiện ra khi main thread (UI thread) bị chặn quá lâu nên app không phản hồi. Các ngưỡng chính: - Không xử lý input event (chạm, phím) trong 5 giây. - BroadcastReceiver.onReceive() chạy quá lâu (10 giây foreground, 60…
RecyclerView là widget hiển thị danh sách/lưới lớn hiệu quả bằng cách tái sử dụng một số ít View thay vì tạo View cho mọi item. Hình dung một cửa sổ chỉ thấy vài dòng: khi cuộn, dòng trôi khỏi màn hình không bị huỷ…
InheritedWidget là widget đặc biệt cho phép các widget con đọc dữ liệu từ tổ tiên mà không phải truyền tay qua từng cấp constructor. Provider, Theme, MediaQuery đều được dựng trên cơ chế này. Hình dung nó như một "trạm phát" đặt cao trên…