Notification ใน Android
Notification คือข้อความแจ้งเตือนที่แสดงนอกแอป (Status Bar, Shade, Lock Screen) ใช้สำหรับแจ้งข่าวสาร, ข้อความ, Download Progress, Media Playback, ฯลฯ
NotificationCompat.Builder: API รองรับทุกเวอร์ชัน
ใช้ androidx.core.app.NotificationCompat.Builder เพื่อรองรับ API เก่าและใหม่ร่วมกัน
Dependency
dependencies {
implementation 'androidx.core:core:1.12.0'
// Material Design Notification (Optional)
implementation 'com.google.android.material:material:1.11.0'
}
ขั้นตอนสร้าง Notification (Modern: API 26+ Requires Channel)
1. สร้าง Notification Channel (API 26+)
private void createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
String channelId = "default_channel";
CharSequence name = "General Notifications";
String description = "General app notifications";
int importance = NotificationManager.IMPORTANCE_DEFAULT;
NotificationChannel channel = new NotificationChannel(channelId, name, importance);
channel.setDescription(description);
channel.enableLights(true);
channel.setLightColor(Color.BLUE);
channel.enableVibration(true);
channel.setVibrationPattern(new long[]{0, 500, 200, 500});
channel.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC);
NotificationManager manager = getSystemService(NotificationManager.class);
manager.createNotificationChannel(channel);
}
}
2. สร้างและแสดง Notification
private void showNotification() {
String channelId = "default_channel";
// Intent เมื่อกด Notification
Intent intent = new Intent(this, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
PendingIntent pendingIntent = PendingIntent.getActivity(
this, 0, intent,
PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT
);
// Action Buttons
Intent replyIntent = new Intent(this, ReplyReceiver.class);
PendingIntent replyPendingIntent = PendingIntent.getBroadcast(
this, 1, replyIntent,
PendingIntent.FLAG_IMMUTABLE
);
// Build Notification
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, channelId)
.setSmallIcon(R.drawable.ic_notification) // Required: Small Icon (White/Transparent)
.setContentTitle("New Message")
.setContentText("You have a new message from John")
.setSubText("2 minutes ago")
.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher_foreground))
.setStyle(new NotificationCompat.BigTextStyle()
.bigText("This is a longer message that will be shown when expanded..."))
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setCategory(NotificationCompat.CATEGORY_MESSAGE)
.setAutoCancel(true) //Dismiss when clicked
.setContentIntent(pendingIntent)
.addAction(R.drawable.ic_reply, "Reply", replyPendingIntent)
.addAction(R.drawable.ic_delete, "Delete", deletePendingIntent)
.setColor(Color.BLUE) // Accent color
.setOnlyAlertOnce(true) // Alert sound/viberate only first time
.setWhen(System.currentTimeMillis());
// Show
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
// Permission Check (Android 13+)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS)
== PackageManager.PERMISSION_GRANTED) {
notificationManager.notify(1, builder.build());
}
} else {
notificationManager.notify(1, builder.build());
}
}
Notification Styles (Style)
1. BigTextStyle (ข้อความยาว)
.setStyle(new NotificationCompat.BigTextStyle()
.bigText("Very long text that will be fully displayed when expanded...")
.setBigContentTitle("Expanded Title")
.setSummaryText("Summary text"))
2. BigPictureStyle (ภาพใหญ่)
.setStyle(new NotificationCompat.BigPictureStyle()
.bigPicture(bitmap)
.bigLargeIcon(null) // Hide large icon when expanded
.setSummaryText("Photo shared"))
3. InboxStyle (รายการหลายบรรทัด)
.setStyle(new NotificationCompat.InboxStyle()
.addLine("Message 1")
.addLine("Message 2")
.addLine("Message 3")
.setBigContentTitle("3 New Messages")
.setSummaryText("+2 more"))
4. MessagingStyle (Chat/Conversation - API 24+)
NotificationCompat.MessagingStyle style = new NotificationCompat.MessagingStyle(
new Person.Builder().setName("Me").setIcon(icon).build()
);
style.setConversationTitle("Group Chat");
style.addMessage("Hello!", System.currentTimeMillis(),
new Person.Builder().setName("John").setIcon(johnIcon).build());
style.addMessage("Hi there!", System.currentTimeMillis(),
new Person.Builder().setName("Jane").setIcon(janeIcon).build());
builder.setStyle(style);
5. MediaStyle (Media Playback)
.setStyle(new NotificationCompat.MediaStyle()
.setMediaSession(mediaSession.getSessionToken())
.setShowActionsInCompactView(0, 1, 2) // Show Play/Pause, Next in compact
.setShowCancelButton(true)
.setCancelButtonIntent(cancelPendingIntent))
Notification Permissions (Android 13+ / API 33+)
// Runtime Permission Request (Activity/Fragment) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { if (ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.POST_NOTIFICATIONS}, REQUEST_CODE_NOTIFICATION_PERMISSION); } }
PendingIntent Flags (สำคัญมาก API 23+)
| Flag | คำอธิบาย |
|---|---|
| FLAG_IMMUTABLE | บังคับ API 23+ ป้องกันการ Mutate Intent (Security) |
| FLAG_MUTABLE | อนุญาตให้แก้ไข Intent ได้ (ใช้เมื่อต้อง Fill ใน ClipData, etc.) |
| FLAG_UPDATE_CURRENT | Update Extra Data ถ้ามี PendingIntent เดียวกันอยู่แล้ว |
| FLAG_CANCEL_CURRENT | Cancel เก่า สร้างใหม่ |
| FLAG_NO_CREATE | ไม่สร้างใหม่ คืนค่า null ถ้ายังไม่มี |
| FLAG_ONE_SHOT | ใช้ครั้งเดียว แล้ว Cancel อัตโนมัติ |
แนะนำ: PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT
จัดการ Notification (Update, Cancel, Group)
Update Notification
// ใช้ ID เดียวกัน (1) และ Notify ใหม่
builder.setContentText("Updated message");
notificationManager.notify(1, builder.build());
Cancel Notification
notificationManager.cancel(1); // Cancel by ID notificationManager.cancelAll(); // Cancel All
Group Notifications (Stack)
String GROUP_KEY = "group_key_messages";
NotificationCompat.Builder builder1 = new NotificationCompat.Builder(this, channelId)
.setGroup(GROUP_KEY)
.setContentTitle("Message 1")
.setContentText("First message");
NotificationCompat.Builder builder2 = new NotificationCompat.Builder(this, channelId)
.setGroup(GROUP_KEY)
.setContentTitle("Message 2")
.setContentText("Second message");
// Summary Notification (Required for Group)
NotificationCompat.Builder summaryBuilder = new NotificationCompat.Builder(this, channelId)
.setGroup(GROUP_KEY)
.setGroupSummary(true)
.setContentTitle("Messages")
.setContentText("2 new messages")
.setStyle(new NotificationCompat.InboxStyle()
.addLine("Message 1")
.addLine("Message 2")
.setBigContentTitle("2 New Messages"));
notificationManager.notify(1, builder1.build());
notificationManager.notify(2, builder2.build());
notificationManager.notify(3, summaryBuilder.build()); // Summary ID ต่างจาก Item
ตัวอย่างครบถ้วน: MainActivity.java
public class MainActivity extends AppCompatActivity {
private static final String CHANNEL_ID = "default_channel";
private static final int NOTIFICATION_ID = 1;
private NotificationManagerCompat notificationManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
createNotificationChannel();
notificationManager = NotificationManagerCompat.from(this);
findViewById(R.id.btnNotify).setOnClickListener(v -> showBasicNotification());
findViewById(R.id.btnBigText).setOnClickListener(v -> showBigTextNotification());
findViewById(R.id.btnProgress).setOnClickListener(v -> showProgressNotification());
}
private void createNotificationChannel() { /* ... โค้ดด้านบน ... */ }
private void showBasicNotification() { /* ... โค้ดด้านบน ... */ }
private void showBigTextNotification() {
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID)
.setSmallIcon(R.drawable.ic_notification)
.setContentTitle("Long Article")
.setContentText("Tap to read more...")
.setStyle(new NotificationCompat.BigTextStyle()
.bigText("Very long article content goes here..."))
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setAutoCancel(true)
.setContentIntent(createPendingIntent());
notify(builder);
}
private void showProgressNotification() {
// สำหรับ Download/Upload Progress
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID)
.setSmallIcon(R.drawable.ic_download)
.setContentTitle("Downloading...")
.setContentText("0%")
.setPriority(NotificationCompat.PRIORITY_LOW)
.setOnlyAlertOnce(true)
.setProgress(100, 0, false); // max, progress, indeterminate
notificationManager.notify(NOTIFICATION_ID, builder.build());
// Simulate Progress
new Thread(() -> {
for (int i = 0; i <= 100; i += 10) {
try { Thread.sleep(500); } catch (InterruptedException ignored) {}
builder.setProgress(100, i, false)
.setContentText(i + "%");
notificationManager.notify(NOTIFICATION_ID, builder.build());
}
builder.setContentText("Complete")
.setProgress(0, 0, false)
.setSmallIcon(R.drawable.ic_done)
.setContentIntent(createPendingIntent())
.setAutoCancel(true);
notificationManager.notify(NOTIFICATION_ID, builder.build());
}).start();
}
private PendingIntent createPendingIntent() {
Intent intent = new Intent(this, MainActivity.class);
return PendingIntent.getActivity(this, 0, intent,
PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT);
}
private void notify(NotificationCompat.Builder builder) {
if (hasNotificationPermission()) {
notificationManager.notify(NOTIFICATION_ID, builder.build());
}
}
private boolean hasNotificationPermission() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
return ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS)
== PackageManager.PERMISSION_GRANTED;
}
return true;
}
}
Best Practices
- Channel ID คงที่ ต่อประเภท Notification (ไม่สร้าง Channel ใหม่ทุกครั้ง)
- Small Icon: White/Transparent Only (Color จะถูก Tint ให้)
- Priority/Importance: ตรงกันระหว่าง Builder และ Channel
- Action Buttons: ไม่เกิน 3 ปุ่ม (Compact View)
- Large Icon: ใช้สำหรับ User Avatar/Contact Photo (Circle)
- Grouping: รวม Notification ประเภทเดียวกัน
- Respect User Settings: ไม่ Spam, ให้ Importance ต่ำถ้าไม่สำคัญ
สรุป
- สร้าง
NotificationChannel(API 26+) - สร้าง
NotificationCompat.Builderพร้อม Channel ID - ตั้งค่า Icon, Title, Text, Style, Action, Intent
- ขอ Permission
POST_NOTIFICATIONS(API 33+) - แสดงด้วย
NotificationManagerCompat.notify(id, notification) - Update/Cancel/Group ด้วย ID เดียวกัน/Group Key