Giải mã InflateException
Hãy coi android.view.InflateException như một lớp vỏ bọc chung. Nó báo hiệu rằng LayoutInflater đã bị lỗi khi cố gắng chuyển đổi mã XML của bạn thành một đối tượng Java hoặc Kotlin. Mặc dù lỗi chỉ ra một dòng cụ thể trong layout của bạn—ví dụ như dòng số 12—nhưng lỗi thực sự thường nằm sâu hơn trong stack trace.
Khi nhật ký (log) hiển thị Error inflating class, hệ thống có khả năng đã thất bại trong việc khởi tạo custom view của bạn. Điều này xảy ra vì một vài lý do: thiếu constructor, lỗi đánh máy trong đường dẫn package, hoặc thậm chí là một sự cố bên trong mã khởi tạo của chính view đó. Bạn cần xem qua vài dòng đầu tiên của lỗi để tìm phần "Caused by".
Các nguyên nhân phổ biến và cách khắc phục
1. Thiếu Constructor (Context, AttributeSet)
Đây là nguyên nhân thường gặp nhất. Khi bạn định nghĩa một view trong XML, hệ thống Android không gọi constructor (Context) đơn giản. Thay vào đó, nó tìm kiếm một constructor chấp nhận cả Context và AttributeSet. Nếu thiếu đối số thứ hai đó, quá trình inflation sẽ thất bại ngay lập tức.
Cách khắc phục (Kotlin): Sử dụng annotation @JvmOverloads. Điều này sẽ tự động tạo tất cả các constructor cần thiết cho bạn.
class CustomView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {
// Logic khởi tạo
}
Cách khắc phục (Java): Bạn phải viết rõ ràng constructor có hai đối số. Hầu hết các nhà phát triển đều triển khai cả ba constructor để đảm bảo an toàn.
public class CustomView extends View {
public CustomView(Context context) { super(context); }
// XML inflation yêu cầu constructor này
public CustomView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
}
2. Đường dẫn Package bị hỏng sau khi Refactor
Di chuyển các tệp tin là một phần bình thường trong quá trình phát triển. Tuy nhiên, nếu bạn di chuyển CustomView.kt từ com.example.ui sang com.example.widgets, Android Studio có thể không cập nhật mọi tệp XML. Một lỗi đánh máy nhỏ trong classpath đầy đủ sẽ làm hỏng trình inflater.
Hãy kiểm tra kỹ tệp XML của bạn. Đảm bảo thẻ (tag) khớp chính xác với cấu trúc package hiện tại:
<!-- Đường dẫn đầy đủ phải chính xác 100% -->
<com.example.widgets.CustomView
android:id="@+id/myCustomView"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
3. Lỗi bên trong khối init
Đôi khi tệp XML hoàn hảo, nhưng mã bên trong view của bạn lại bị lỗi. Nếu khối init hoặc constructor của bạn cố gắng truy cập một đối tượng null hoặc một tài nguyên (resource) bị thiếu, hệ thống sẽ báo cáo đó là lỗi inflation. Điều này thường xảy ra khi các nhà phát triển cố gắng sử dụng Resources.getColor() với một ID phụ thuộc vào theme chưa có sẵn tại thời điểm đó.
Kiểm tra Logcat của bạn để tìm dòng "Caused by" thứ hai hoặc thứ ba. Nếu bạn thấy NullPointerException hoặc Resources$NotFoundException, vấn đề nằm ở logic của bạn, không phải ở chính tệp layout.
4. Thu gọn mã với R8 và Proguard
Ứng dụng hoạt động ở chế độ Debug nhưng lại bị lỗi ở bản Release? Điều này thường có nghĩa là R8 (trình thu gọn mã) đã xóa constructor custom view của bạn vì nó nghĩ rằng không có ai sử dụng nó. Vì inflation sử dụng reflection, R8 không phải lúc nào cũng thấy được mối liên hệ giữa tệp XML và mã của bạn.
Thêm một quy tắc "keep" vào tệp proguard-rules.pro để bảo vệ các view của bạn:
# Giữ lại tất cả các view và constructor của chúng
-keep class com.example.widgets.** { *; }
# Hoặc giữ lại các class cụ thể nếu bạn muốn chính xác hơn
-keep class com.example.CustomView { <init>(...); }
Cách tìm nguyên nhân gốc rễ nhanh chóng
Đừng lãng phí thời gian để đoán. Hãy làm theo quy trình sau để cô lập lỗi:
- **Quét Stack Trace:** Tìm mục "Caused by" **cuối cùng**. Đây chính là lỗi thực sự đã kích hoạt phản ứng dây chuyền.
- **Xác minh số dòng:** Nếu nhật ký báo `line #14`, hãy mở tệp XML và đếm. Dòng đó có thực sự là custom view của bạn không?
- **Kiểm tra Layout Preview:** Nếu view không hiển thị trong tab Design của Android Studio, vấn đề có khả năng nằm ở constructor hoặc phương thức `onDraw` của bạn.
- **Kiểm tra với một View chuẩn:** Tạm thời thay thế custom view của bạn bằng một `FrameLayout`. Nếu sự cố dừng lại, vấn đề chắc chắn nằm bên trong class tùy chỉnh của bạn.
Kiểm tra cuối cùng
Sau khi bạn áp dụng bản sửa lỗi, hãy làm theo các bước sau để đảm bảo nó hoạt động ổn định:
- **Clean và Rebuild:** Sử dụng `Build > Clean Project` để xóa bỏ các tệp cũ (artifacts).
- **Kiểm tra trên các mức API khác nhau:** Một số lỗi inflation chỉ xuất hiện trên các phiên bản Android cũ hơn (API 21 so với API 33) do cách xử lý tài nguyên.
- **Kiểm tra Logcat:** Điều hướng đến màn hình gặp sự cố. Nếu nhật ký không còn lỗi, bạn đã giải quyết xong.

