Non-Fatal Error trong ứng dụng di động — bản chất, loại và xử lý lỗi

Tác giả: IT Sectr Đã đăng: 2026-05-27 Thời gian đọc: 8 phút

Non-Fatal Error — là lỗi không làm kết thúc ứng dụng và cho phép tiếp tục thực thi chương trình. Không giống như lỗi nghiêm trọng, lỗi không nghiêm trọng có thể được bắt, xử lý và ghi log mà không mất phiên người dùng. Theo Tài liệu Firebase Crashlytics, 2024, khoảng 70% tất cả lỗi được ghi lại trong ứng dụng sản xuất là không nghiêm trọng, nhưng bỏ qua chúng dẫn đến tích tụ nợ kỹ thuật và suy giảm dần trải nghiệm người dùng. Xử lý đúng cách các lỗi không nghiêm trọng là một trong những kỹ năng quan trọng của nhà phát triển di động.

Những điểm chính

  • Non-Fatal Error — lỗi không kết thúc ứng dụng và cho phép khôi phục thực thi
  • Xử lý lỗi không nghiêm trọng bao gồm try-catch, ghi log và hiển thị giao diện dự phòng
  • Ghi log lỗi không nghiêm trọng rất quan trọng để tìm lỗi ẩn trong sản xuất
  • Fatal Error — ngược lại: lỗi gây ra sự cố ứng dụng không thể khôi phục
  • Crashlytics và Sentry cho phép theo dõi lỗi không nghiêm trọng theo thời gian thực

Non-Fatal Error là gì

Non-Fatal Error — là một ngoại lệ hoặc trạng thái lỗi không gây ra việc kết thúc tiến trình. Ứng dụng tiếp tục hoạt động, nhưng có thể ở trạng thái không chính xác: dữ liệu không tải được, yêu cầu không được gửi, phần tử giao diện không hiển thị. Người dùng hoặc không nhận thấy lỗi, hoặc thấy thông báo và tiếp tục sử dụng ứng dụng.

Đặc điểm chính

Lỗi không nghiêm trọng luôn để lại cho chương trình một con đường khôi phục. Trình xử lý lỗi có thể cung cấp dữ liệu thay thế, thử lại thao tác hoặc hiển thị phần giữ chỗ giao diện. Mục tiêu chính là ngăn chặn sự cố và duy trì trải nghiệm người dùng chấp nhận được. Nhà phát triển phải lên kịch bản khôi phục rõ ràng trong mỗi khối catch.

Vai trò trong sự ổn định của ứng dụng

Theo Instabug 2024, 65% người dùng gỡ cài đặt ứng dụng sau hai tương tác thất bại. Các lỗi không nghiêm trọng bị bỏ qua sẽ tích tụ và làm giảm chất lượng tổng thể. Việc ghi log và sửa lỗi không nghiêm trọng một cách có hệ thống là con đường trực tiếp để cải thiện tỷ lệ giữ chân người dùng và điểm đánh giá trên cửa hàng ứng dụng.

Các loại lỗi không nghiêm trọng

Lỗi mạng là loại lỗi không nghiêm trọng phổ biến nhất trong ứng dụng di động. Hết thời gian chờ kết nối, mất mạng, mã trạng thái máy chủ không chính xác — tất cả các tình huống này đều được bắt và xử lý mà không gây sự cố. Người dùng được hiển thị thông báo dịch vụ không khả dụng với tùy chọn thử lại. Mẫu thử lại với backoff theo cấp số nhân là điển hình cho lỗi mạng.

Lỗi xác thực dữ liệu

Định dạng phản hồi máy chủ không chính xác, thiếu trường bắt buộc, kiểu dữ liệu không hợp lệ — lỗi phân tích cú pháp là không nghiêm trọng nếu ứng dụng xử lý dữ liệu sai một cách chính xác. Cách tiếp cận điển hình là sử dụng giá trị dự phòng mặc định và ghi log lỗi phân tích với ngữ cảnh yêu cầu để phân tích sau ở phía máy chủ.

Lỗi hiển thị giao diện

Sự cố tải hình ảnh, phông chữ không chính xác, lỗi bố cục — tất cả đều không nghiêm trọng nhưng làm giảm trải nghiệm người dùng. Hình ảnh giữ chỗ và giá trị dự phòng giúp tránh màn hình trống và làm cho lỗi ít bị chú ý hơn. Trong React Native, Error Boundary được sử dụng cho lỗi giao diện với việc hiển thị thành phần dự phòng.

Lỗi logic nghiệp vụ và trạng thái

Lỗi tính toán, không khớp trạng thái, chuyển đổi màn hình không chính xác — lỗi logic thường không gây ra sự cố nhưng dẫn đến hành vi không chính xác của ứng dụng. Chúng khó phát hiện hơn nếu không có ghi log và giám sát có hệ thống vì không tạo báo cáo sự cố và không bị phát hiện cho đến khi có khiếu nại của người dùng.

Non-Fatal Error vs Fatal Error: so sánh

Non-Fatal Error khác với lỗi nghiêm trọng ở chỗ nó để lại cho chương trình cơ hội tiếp tục hoạt động. Lỗi nghiêm trọng là trạng thái mà ứng dụng không thể khôi phục: giải tham chiếu con trỏ null, tràn ngăn xếp, hết bộ nhớ. Lỗi không nghiêm trọng có thể được bắt, xử lý và tiếp tục thực thi, trong khi lỗi nghiêm trọng yêu cầu khởi động lại ứng dụng.

Đặc điểmNon-Fatal ErrorFatal Error
Kết thúc ứng dụngKhông
Khả năng khôi phụcCó, qua khối catchKhông
Ghi logTừ mã qua recordExceptionChỉ bởi trình báo cáo sự cố
Tác động UXBất tiện tạm thờiThất bại hoàn toàn phiên
Ví dụHết thời gian mạng, lỗi phân tíchNullPointerException, OOM

Ranh giới giữa không nghiêm trọng và nghiêm trọng có thể phụ thuộc vào cách triển khai. Hết thời gian mạng trong một ứng dụng được xử lý như không nghiêm trọng (thử lại sau 1–2 giây), trong khi ở ứng dụng khác, nó có thể là nghiêm trọng (sự cố nếu không có trình xử lý). Xử lý lỗi chất lượng cao biến các tình huống tiềm ẩn nghiêm trọng thành không nghiêm trọng, tăng độ ổn định của ứng dụng. Thiết kế hệ thống xử lý lỗi là một trong những nhiệm vụ kiến trúc chính khi phát triển ứng dụng di động với yêu cầu độ tin cậy cao. Một hệ thống giám sát tích hợp cho phép nhóm phát hiện và sửa lỗi không nghiêm trọng nhanh chóng trước khi chúng ảnh hưởng đến một số lượng lớn người dùng.

Ghi log lỗi không nghiêm trọng

Firebase Crashlytics là công cụ chính để ghi log lỗi không nghiêm trọng trong ứng dụng di động. Phương thức recordException cho phép ghi lại một ngoại lệ không nghiêm trọng với dấu vết ngăn xếp đầy đủ và ngữ cảnh thực thi mà không làm gián đoạn ứng dụng. Không giống như báo cáo sự cố, recordException có thể được gọi ở bất kỳ đâu trong mã để ghi log các ngoại lệ đã bắt.

kotlin
fun fetchUserData(userId: String) {
    try {
        val response = apiService.getUser(userId)
        updateUI(response)
    } catch (e: IOException) {
        Crashlytics.log("Network error for user $userId")
        Crashlytics.recordException(e)
        showRetryDialog()
    } catch (e: JsonParseException) {
        // Non-fatal: sử dụng dữ liệu dự phòng
        Crashlytics.recordException(e)
        showFallbackContent()
    }
}

// Ghi log với khóa tùy chỉnh
Crashlytics.setCustomKey("screen", "Profile")
Crashlytics.setCustomKey("api_version", "v3")

Sentry là một giải pháp thay thế cho Crashlytics với chẩn đoán chi tiết hơn cho lỗi không nghiêm trọng. SDK Sentry cung cấp phương thức captureException, gửi chi tiết ngoại lệ đến máy chủ. Ưu điểm chính của Sentry là nhóm các lỗi không nghiêm trọng tương tự thành một vấn đề duy nhất, phân tích tần suất lặp lại và cung cấp ngữ cảnh thực thi dưới dạng breadcrumbs — chuỗi hành động của người dùng trước khi xảy ra lỗi.

Tiêu chí ghi log lỗi không nghiêm trọng

Không phải tất cả lỗi không nghiêm trọng đều cần được ghi log. Trạng thái dự kiến — lỗi mạng khi không có kết nối — có thể được ghi log có chọn lọc. Lỗi không mong đợi — NullPointerException trong mã đã xử lý, định dạng dữ liệu không hợp lệ, lỗi logic — phải luôn được ghi log. Mỗi nhóm xác định ngưỡng quan trọng của riêng mình: trung bình, 10 đến 20 lỗi không nghiêm trọng duy nhất trên 1000 người dùng mỗi ngày được coi là bình thường. Việc thiết lập cảnh báo cho sự gia tăng đột biến lỗi không nghiêm trọng là rất quan trọng — điều này có thể chỉ ra vấn đề với phiên bản API mới hoặc hồi quy sau khi phát hành.

Xử lý lỗi không nghiêm trọng trong mã

Cơ chế xử lý cơ bản là try-catch, bắt ngoại lệ và thực thi mã khôi phục. Đối với thao tác mạng, mẫu điển hình là thử lại với backoff theo cấp số nhân. Đối với lỗi phân tích, cách tiếp cận là sử dụng giá trị dự phòng mặc định và ghi log ngữ cảnh để phân tích sau ở phía máy chủ.

swift
func loadImage(from url: URL) -> UIImage? {
    do {
        let data = try Data(contentsOf: url)
        return UIImage(data: data)
    } catch {
        Logger.shared.logError(error: "Image load failed: \(url)")
        return UIImage(named: "placeholder")
    }
}

func performRequest() async throws -> Data {
    var lastError: Error? = nil
    for attempt in 0..<3 {
        do {
            return try await URLSession.shared.data(from: url)
        } catch {
            lastError = error
            try await Task.sleep(UInt64(pow(2, attempt)) * 1_000_000_000)
        }
    }
    throw lastError ?? URLError(.unknown)
}

Kiểu Result — một cách tiếp cận thay thế không có ngoại lệ. Một hàm trả về lớp sealed Result với các biến thể Success và Failure. Mã gọi xử lý cả hai biến thể một cách rõ ràng, loại bỏ các lỗi không được xử lý. Kiểu Result phổ biến trong Kotlin (Result trong thư viện chuẩn) và Swift (Result) để xử lý rõ ràng các trạng thái không nghiêm trọng ở cấp độ kiểu.

Chiến lược dự phòng cho lỗi không nghiêm trọng

Đối với mỗi loại lỗi không nghiêm trọng, cần lên kế hoạch chiến lược khôi phục: tải dữ liệu được lưu trong bộ nhớ đệm khi lỗi mạng, sử dụng giá trị mặc định khi lỗi phân tích, khởi tạo lại thành phần khi lỗi giao diện. Một thực hành tốt là hiển thị cho người dùng toast hoặc snackbar với thông báo lỗi mà không chặn hoàn toàn tương tác với ứng dụng. Điều quan trọng là phân biệt giữa lỗi có thể khôi phục và không thể khôi phục — đối với loại sau, chiến lược khôi phục sẽ khác, như đề xuất khởi động lại màn hình hoặc xóa dữ liệu. Lưu trạng thái thành công trước đó vào bộ nhớ đệm thường là cách đơn giản và hiệu quả nhất để xử lý lỗi không nghiêm trọng trên các nền tảng di động.

Câu hỏi thường gặp

Lỗi không nghiêm trọng khác với cảnh báo như thế nào?

Cảnh báo là lời cảnh báo của trình biên dịch hoặc trình phân tích tĩnh về một vấn đề tiềm ẩn trong mã. Lỗi không nghiêm trọng là ngoại lệ thời gian chạy đã xảy ra nhưng không gây ra sự cố. Cảnh báo có thể được sửa trước khi biên dịch; lỗi không nghiêm trọng phải được xử lý trong quá trình thực thi thông qua khối catch.

Có nên ghi log tất cả lỗi không nghiêm trọng không?

Không, ghi log quá mức làm lộn xộn việc giám sát. Lỗi không mong đợi trong sản xuất nên được ghi log, trong khi trạng thái dự kiến nên được bỏ qua: lỗi mạng khi ngoại tuyến có thể được ghi log có chọn lọc, nhưng NullPointerException trong mã đã xử lý phải luôn được ghi log. Mỗi nhóm xác định ngưỡng quan trọng dựa trên ngữ cảnh của ứng dụng.

Làm thế nào để xử lý lỗi không nghiêm trọng trong SwiftUI?

Trong SwiftUI, ObservableObject với trường @Published errorState được sử dụng để theo dõi trạng thái lỗi. View đăng ký thay đổi và hiển thị nội dung thay thế. Trước iOS 17, Combine với trình xử lý được sử dụng; từ iOS 17 trở đi, SwiftData và macro @Observable được sử dụng để cập nhật giao diện phản ứng.

Lỗi không nghiêm trọng có thể trở thành nghiêm trọng không?

Có, nếu lỗi gây ra phản ứng dây chuyền. Ví dụ: lỗi tải hình ảnh không nghiêm trọng có thể dẫn đến trạng thái giao diện không chính xác, sau đó gây ra sự cố khi cố gắng hiển thị. Xử lý lỗi không nghiêm trọng chất lượng cao ở mỗi cấp độ ngăn chặn chúng leo thang lên mức nghiêm trọng.

Non-fatal khác nhau như thế nào giữa iOS và Android?

Trên iOS, lỗi không nghiêm trọng được xử lý qua do-catch với throw; trên Android, qua try-catch với ngoại lệ. iOS sử dụng NSError với miền và mã lỗi; Android sử dụng ngoại lệ Java/Kotlin. Crashlytics hoạt động giống hệt nhau trên cả hai nền tảng qua recordException, cung cấp giao diện giám sát thống nhất.

Tổng kết

  • Non-Fatal Error — lỗi thời gian chạy không kết thúc ứng dụng và cho phép khôi phục thực thi
  • Lỗi mạng, lỗi phân tích và lỗi hiển thị giao diện — ba lớp chính của lỗi không nghiêm trọng
  • Fatal Error — ngược lại với non-fatal, gây ra sự cố ứng dụng hoàn toàn không thể khôi phục
  • Crashlytics và Sentry — công cụ chính để ghi log lỗi không nghiêm trọng trong sản xuất
  • Kiểu Result — giải pháp thay thế cho ngoại lệ để xử lý rõ ràng trạng thái lỗi ở cấp độ kiểu
  • Giá trị giữ chỗ và chiến lược dự phòng ngăn chặn sự suy giảm rõ rệt của trải nghiệm người dùng
  • Sửa chữa có hệ thống lỗi không nghiêm trọng cải thiện tỷ lệ giữ chân và chất lượng ứng dụng theo Instabug

Chúng tôi sẽ phát triển ứng dụng di động chìa khóa trao tay

IT Sectr tạo các ứng dụng iOS và Android cho các công ty khởi nghiệp và doanh nghiệp từ năm 2017. Chúng tôi sẽ tư vấn và đề xuất giải pháp tốt nhất cho bạn.

Thảo luận dự án

Đọc thêm