Giới thiệu
Bài tập trung vào việc cấu hình PendingIntent và Intent flags để đảm bảo bấm thông báo **resume (tiếp tục)** Activity hiện có thay vì tạo instance mới.
So sánh các phương pháp
| Phương pháp | Kết quả |
|---|---|
| Không set flag | Tạo Activity mới mỗi lần bấm (nhiều instance trong stack) |
| FLAG_ACTIVITY_CLEAR_TOP | Xóa các Activity trên đỉnh, nhưng vẫn tạo mới nếu chưa có |
| FLAG_ACTIVITY_SINGLE_TOP | Không tạo mới nếu đang ở đỉnh, nhưng không xóa các Activity khác |
| CLEAR_TOP + SINGLE_TOP (Khuyên dùng) | Resume instance hiện có, xóa stack phía trên, gọi onNewIntent() |
| android:launchMode="singleTop" (Manifest) | Tương tự SINGLE_TOP, nhưng áp dụng toàn cục |
| android:launchMode="singleTask" | Chỉ 1 instance per task, xóa stack phía trên, nhưng có thể thay đổi task root |
Code chuẩn (Best Practice)
1. Intent flags
Intent intent = new Intent(context, TargetActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
// Thêm data phân biệt
intent.putExtra("source", "notification");
intent.putExtra("data_id", itemId);
2. PendingIntent flags
PendingIntent pendingIntent = PendingIntent.getActivity(
context,
requestCode, // Dùng requestCode khác nhau cho các action khác nhau
intent,
PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT
);
FLAG_UPDATE_CURRENT: Cập nhật extra data trong intent nếu PendingIntent đã tồn tại. Rất quan trọng khi gửi nhiều thông báo cùng target nhưng data khác nhau.
3. Xử lý trong Activity đích
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
// Luôn setIntent mới để getIntent() trả về data mới
setIntent(intent);
if ("notification".equals(intent.getStringExtra("source"))) {
int itemId = intent.getIntExtra("data_id", -1);
// Load data, cập nhật UI
loadItemDetail(itemId);
}
}
@Override
protected void onResume() {
super.onResume();
// Xử lý chung cho cả cold start và resume
handleIntent(getIntent());
}
private void handleIntent(Intent intent) {
if (intent != null && "notification".equals(intent.getStringExtra("source"))) {
int itemId = intent.getIntExtra("data_id", -1);
if (itemId != -1) loadItemDetail(itemId);
}
}
Các lỗi thường gặp
- Quên FLAG_UPDATE_CURRENT: Tất cả thông báo mang data của cái đầu tiên.
- Dùng requestCode = 0 cho mọi thứ: Các action khác nhau (mở chat, mở profile) ghi đè nhau.
- Không gọi setIntent() trong onNewIntent: getIntent() vẫn trả về intent cũ.
- Dùng FLAG_MUTABLE không cần thiết: Rủi ro bảo mật từ API 31.
Kiểm thử
- Mở app → điều hướng A → B → C.
- Gửi thông báo trỏ về C.
- Bấm thông báo → C hiển thị, A&B bị xóa, onNewIntent() được gọi.
- Bấm Back → về Home (không về B).