Giới thiệu
Thông báo cục bộ do ứng dụng tự tạo và hiển thị, không cần server push. Phù hợp cho: nhắc nhở, alarm, kết quả download, hoàn thành task nền.
So sánh Local vs Push Notification
| Đặc điểm | Local Notification | Push Notification (FCM) |
|---|---|---|
| Nguồn | App tự tạo | Server gửi qua FCM |
| Yêu cầu mạng | Không cần | Cần internet |
| Độ trễ | Ngay lập tức / theo lịch | Tùy network, FCM |
| Chi phí | Miễn phí hoàn toàn | Miễn phí (FCM) nhưng cần backend |
| App đóng vẫn hoạt động | Cần Service/WorkManager/Alarm | Luôn hoạt động (FCM wake up) |
3 Cách tạo Local Notification phổ biến
1. Ngay lập tức (Instant) - Demo ở bài trước
Gọi NotificationManager.notify() trực tiếp trong Activity/Fragment.
2. Đặt lịch một lần (AlarmManager + BroadcastReceiver)
Xem chi tiết bài "How to schedule local notifications in Android" (ID 1003061557).
3. Định kỳ (WorkManager - Khuyên dùng cho API 23+)
// Worker class
public class NotificationWorker extends Worker {
public NotificationWorker(@NonNull Context context, @NonNull WorkerParameters params) {
super(context, params);
}
@NonNull
@Override
public Result doWork() {
showNotification("Đồng bộ định kỳ", "Đã kiểm tra cập nhật lúc " + new Date());
return Result.success();
}
private void showNotification(String title, String text) {
NotificationManager manager = (NotificationManager) getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE);
NotificationCompat.Builder builder = new NotificationCompat.Builder(getApplicationContext(), "work_channel")
.setSmallIcon(R.drawable.ic_launcher_foreground)
.setContentTitle(title)
.setContentText(text)
.setAutoCancel(true);
// Channel setup...
manager.notify((int) System.currentTimeMillis(), builder.build());
}
}
// Đăng ký chạy mỗi 15 phút (tối thiểu)
PeriodicWorkRequest request = new PeriodicWorkRequest.Builder(NotificationWorker.class, 15, TimeUnit.MINUTES)
.build();
WorkManager.getInstance(context).enqueue(request);
Code mẫu hoàn chỉnh (Instant Local Notification)
Giống bài 1003061554, nhưng bổ sung xin quyền runtime cho Android 13+:
MainActivity.java (có xin quyền)
package com.example.localnotificationfull;
import android.Manifest;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.app.NotificationCompat;
import androidx.core.content.ContextCompat;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
private static final String CHANNEL_ID = "local_full_channel";
private static final int REQ_POST_NOTIF = 1001;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button btn = findViewById(R.id.btnCreateNotification);
btn.setOnClickListener(v -> {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { // API 33
if (ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.POST_NOTIFICATIONS}, REQ_POST_NOTIF);
return;
}
}
sendNotification();
});
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == REQ_POST_NOTIF && grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
sendNotification();
} else {
Toast.makeText(this, "Cần quyền gửi thông báo", Toast.LENGTH_SHORT).show();
}
}
private void sendNotification() {
NotificationManager manager = getSystemService(NotificationManager.class);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID)
.setSmallIcon(R.drawable.ic_launcher_foreground)
.setContentTitle("Local Notification")
.setContentText("Đã xin quyền runtime cho Android 13+")
.setAutoCancel(true)
.setPriority(NotificationCompat.PRIORITY_DEFAULT);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(
CHANNEL_ID, "Local Full", NotificationManager.IMPORTANCE_DEFAULT);
manager.createNotificationChannel(channel);
}
manager.notify((int) System.currentTimeMillis(), builder.build());
}
}
Tóm tắt checklist
- [ ] Tạo Notification Channel (API 26+)
- [ ] setSmallIcon() - bắt buộc
- [ ] setContentTitle() + setContentText()
- [ ] setAutoCancel(true) cho thông báo tương tác
- [ ] Xin quyền POST_NOTIFICATIONS runtime (API 33+)
- [ ] Dùng WorkManager cho tác vụ định kỳ/lặp lại
- [ ] Dùng AlarmManager.setExact() cho báo thức chính xác