Để tự động hủy một notification sau một khoảng thời gian cố định (ví dụ: 5 giây), sử dụng Handler.postDelayed() kết hợp NotificationManager.cancel(notificationId).
Các bước thực hiện
Bước 1: Tạo dự án mới
Package: app.tutorialspoint.com.notifyme.
Bước 2: Giao diện (res/layout/activity_main.xml)
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="https://schemas.android.com/apk/res/android"
xmlns:app="https://schemas.android.com/apk/res-auto"
xmlns:tools="https://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp"
tools:context=".MainActivity">
<Button
android:id="@+id/btnCreateNotification"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="Tạo Notification tự xóa sau 5s"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
Bước 3: Logic tự xóa (src/MainActivity.java)
package app.tutorialspoint.com.notifyme;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import androidx.core.app.NotificationCompat;
import androidx.appcompat.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
public class MainActivity extends AppCompatActivity {
public static final String NOTIFICATION_CHANNEL_ID = "10001";
private static final String DEFAULT_CHANNEL_ID = "default";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button btnCreateNotification = findViewById(R.id.btnCreateNotification);
btnCreateNotification.setOnClickListener(v -> createAutoDismissNotification());
}
private void createAutoDismissNotification() {
// Intent khi bấm vào notification
Intent notificationIntent = new Intent(this, MainActivity.class);
notificationIntent.addCategory(Intent.CATEGORY_LAUNCHER);
notificationIntent.setAction(Intent.ACTION_MAIN);
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent resultIntent = PendingIntent.getActivity(
this, 0, notificationIntent, PendingIntent.FLAG_IMMUTABLE);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, DEFAULT_CHANNEL_ID)
.setSmallIcon(R.drawable.ic_launcher_foreground)
.setContentTitle("Thông báo tự động xóa")
.setContentText("Notification này sẽ tự biến mất sau 5 giây")
.setStyle(new NotificationCompat.InboxStyle())
.setContentIntent(resultIntent)
.setAutoCancel(true);
NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
// Tạo channel nếu cần (Android 8+)
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
int importance = NotificationManager.IMPORTANCE_HIGH;
NotificationChannel channel = new NotificationChannel(
NOTIFICATION_CHANNEL_ID, "Kênh tự xóa", importance);
builder.setChannelId(NOTIFICATION_CHANNEL_ID);
if (manager != null) {
manager.createNotificationChannel(channel);
}
}
// ID duy nhất cho notification này
final int notificationId = (int) System.currentTimeMillis();
// Hiển thị notification
if (manager != null) {
manager.notify(notificationId, builder.build());
}
// Lên lịch xóa sau 5 giây (5000 ms)
long delayMs = 5000;
new Handler().postDelayed(() -> {
if (manager != null) {
manager.cancel(notificationId);
}
}, delayMs);
}
}
Bước 4: AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="https://schemas.android.com/apk/res/android"
package="app.tutorialspoint.com.notifyme">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Giải thích cơ chế
notificationId: Phải lưu lại giá trị ID dùng trongnotify(id, ...)để sau đó gọicancel(id)chính xác.Handler.postDelayed(Runnable, delayMs): Đặt một task chạy trên main thread saudelayMsmilliseconds.manager.cancel(id): Xóa notification cụ thể. Dùngmanager.cancelAll()để xóa tất cả notification của app.
Cách hiện đại hơn (API 26+): Timeout trong NotificationChannel
Từ Android 8.0, có thể đặt timeout trực tiếp trên Channel (áp dụng cho tất cả notification trong kênh):
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(
"auto_dismiss_channel", "Tự xóa", NotificationManager.IMPORTANCE_DEFAULT);
// Tự xóa sau 10 giây (10000 ms)
channel.setTimeoutAfter(10000);
manager.createNotificationChannel(channel);
builder.setChannelId("auto_dismiss_channel");
}
Ưu điểm: Không cần Handler, hệ thống tự quản lý, tiết kiệm tài nguyên.
Nhược điểm: Áp dụng cho toàn bộ kênh, không linh hoạt cho từng notification.
So sánh các phương pháp
| Phương pháp | API Level | Độ linh hoạt | Ghi chú |
|---|---|---|---|
Handler.postDelayed + cancel() | Tất cả | Cao (mỗi notif khác nhau) | Cần quản lý ID, Handler leak nếu Activity destroy |
Channel.setTimeoutAfter() | 26+ | Thấp (cả kênh) | Hệ thống tự xử lý, an toàn hơn |
WorkManager / AlarmManager | Tất cả | Cao | Phức tạp hơn, dùng cho trường hợp phức tạp |
Tránh memory leak với Handler
Nếu Activity bị destroy trước khi delay kết thúc, Handler vẫn giữ reference. Giải pháp:
// Dùng static Handler hoặc WeakReference private static final Handler sHandler = new Handler(Looper.getMainLooper()); // Hoặc dùng Runnable reference để removeCallbacks private final Runnable dismissRunnable = () -> manager.cancel(notificationId); sHandler.postDelayed(dismissRunnable, delayMs); // Trong onDestroy(): sHandler.removeCallbacks(dismissRunnable);
Hoặc tốt hơn: dùng androidx.lifecycle.LifecycleObserver hoặc Coroutines lifecycleScope.launch { delay(5000); manager.cancel(id) }.