Một Activity nhận số lượng qua Intent và dùng 0 làm default. Khi không có extra, UI hiển thị giống hệt trường hợp bên gửi chủ động truyền số 0. Nếu hai tình huống có ý nghĩa khác nhau, default đã che mất một phần thông tin.
Bài dành cho project Android Kotlin có Activity đang khai báo trong manifest. Các API hasExtra và getIntExtra có từ API level 1; tài liệu được đối chiếu ngày 01/11/2026. Mẫu được rà theo hợp đồng API, chưa chạy Kotlin/Android build hoặc instrumentation test.
1. Xác định ba trạng thái trước khi chọn default
Giả sử quy tắc demo cho phép số lượng nguyên từ 0 đến 99. Không truyền dữ liệu là Missing; truyền Int trong phạm vi là Valid; dữ liệu có mặt nhưng không đọc được Int phù hợp hoặc ngoài phạm vi là Invalid.
Quy tắc 0–99 là lựa chọn của ví dụ, không phải giới hạn của Intent. Nhờ phạm vi đó, -1 có thể dùng làm giá trị đọc mặc định nằm ngoài miền hợp lệ. Nếu nghiệp vụ cho phép mọi Int, cần một biểu diễn khác để tránh va chạm sentinel với giá trị thật.
2. Đọc sự hiện diện trước, rồi kiểm tra giá trị
Đặt helper dưới trong cùng package với code sử dụng. Tên key có prefix để giảm khả năng đụng tên; trong ứng dụng thật dùng prefix thuộc namespace của dự án và thống nhất nó ở cả bên gửi lẫn bên nhận.
import android.content.Intent
const val EXTRA_COUNT = "net.aedev.demo.COUNT"
sealed class CountExtra {
object Missing : CountExtra()
data class Valid(val value: Int) : CountExtra()
object Invalid : CountExtra()
}
fun Intent.readCountExtra(): CountExtra {
if (!hasExtra(EXTRA_COUNT)) return CountExtra.Missing
val count = getIntExtra(EXTRA_COUNT, -1)
return if (count in 0..99) {
CountExtra.Valid(count)
} else {
CountExtra.Invalid
}
}
Theo tài liệu, getIntExtra dùng default khi không có giá trị thuộc kiểu được yêu cầu dưới key đó. hasExtra trả lời key có mặt, không chứng minh kiểu hoặc miền giá trị đã đúng. Vì vậy cả hai bước vẫn có vai trò riêng.
Ví dụ không cố biến chuỗi "0" thành Int. Nếu hợp đồng giữa hai component nói kiểu Int, bên gửi nên dùng đúng overload putExtra cho Int. Chuyển đổi ngầm nhiều dạng dữ liệu ở bên nhận có thể làm lỗi tích hợp khó phát hiện hơn.
3. Xử lý kết quả tại Activity
Trong code nhận Intent, chuyển ba trạng thái thành quyết định UI rõ ràng. Fragment sau dùng trong Activity có sẵn; biến message có thể đưa vào TextView hoặc state màn hình đang dùng.
val message = when (val result = intent.readCountExtra()) {
CountExtra.Missing -> "Chưa truyền số lượng"
CountExtra.Invalid -> "Số lượng không hợp lệ"
is CountExtra.Valid -> "Số lượng: ${result.value}"
}
Ở bên gửi, một giá trị 0 hợp lệ được truyền như sau. MainActivity là lớp Activity nhận trong project của bạn, không phải một component có sẵn của Android. Đặt đoạn này ở nơi có biến context hợp lệ.
val request = Intent(context, MainActivity::class.java)
.putExtra(EXTRA_COUNT, 0)
context.startActivity(request)
Mẫu giả định luồng mở Activity thông thường từ context phù hợp. Nó không thiết lập launchMode hoặc xử lý một Activity được tái sử dụng qua onNewIntent; nếu dự án có luồng đó, đọc extra từ Intent mới ở entry point tương ứng.
4. Thử thiếu, 0, biên và sai kiểu
Trong Android test chạy trên runtime thích hợp, tạo Intent không extra, Intent mang Int 0, Int 99, Int -1, Int 100 và String "0". Kiểm tra Missing chỉ xuất hiện ở ca không có key, Valid giữ được 0/99 và các ca còn lại bị từ chối theo chính sách demo.
Đây là danh sách ca cần chạy khi tích hợp, không phải kết quả instrumentation đã thu từ bài này. Các lớp Intent của Android không trở thành một implementation đầy đủ chỉ vì test JVM có thể import tên lớp; cần chọn môi trường test đúng với project.
Nếu đổi miền hợp lệ để nhận -1, phải xem lại default của helper và các ca kiểm tra trước khi sửa một điều kiện range. Một sentinel chỉ an toàn khi nó thật sự nằm ngoài miền giá trị cần phân biệt.
Lỗi thường gặp và giới hạn
Không dùng count != 0 để suy ra extra đã được truyền, vì nó loại nhầm giá trị hợp lệ 0. Không dùng riêng hasExtra để bỏ qua validation. Cũng không coi giá trị trong Intent là bằng chứng người gửi có quyền thực hiện nghiệp vụ; kiểm tra đầu vào và kiểm tra quyền là hai trách nhiệm khác nhau.
Mẫu chỉ đọc một primitive extra, không phải bộ giải mã tổng quát cho Parcelable hoặc dữ liệu phức tạp từ bên ngoài. Bắt đầu từ hợp đồng key, kiểu và phạm vi giúp code nhận giữ được khác biệt giữa “không có” và “có nhưng không hợp lệ”.

