Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Android

วิธีเล่นเสียงปรับแต่งเองเมื่อรับ Notification ใน Android

ภาพรวม

ตัวอย่างนี้สาธิตการให้ผู้ใช้เลือกเสียงแจ้งเตือน (Ringtone) เองผ่าน RingtoneManager แล้วนำไปใช้กับ Notification

ขั้นตอนที่ 1: สร้างโปรเจกต์ใหม่

Android Studio → File → New Project

ขั้นตอนที่ 2: Layout (activity_main.xml) - มีปุ่มเลือกเสียงและสร้าง Notification

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="https://schemas.android.com/apk/res/android"
    xmlns:tools="https://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <Button
        android:onClick="setRingtone"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="32dp"
        android:text="set ringtone" />

    <Button
        android:onClick="createNotification"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:layout_margin="16dp"
        android:text="Create notification" />
</RelativeLayout>

ขั้นตอนที่ 3: MainActivity - เลือกและใช้ Ringtone

package app.tutorialspoint.com.notifyme;

import android.app.Activity;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.content.Intent;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.NotificationCompat;
import android.support.v7.app.AppCompatActivity;
import android.view.View;

public class MainActivity extends AppCompatActivity {
    public static final String NOTIFICATION_CHANNEL_ID = "10001";
    private final static String default_notification_channel_id = "default";
    private String chosenRingtone; // เก็บ URI เสียงที่เลือก

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        onNewIntent(getIntent());
    }

    // เปิด Ringtone Picker ให้ผู้ใช้เลือกเสียง
    public void setRingtone(View view) {
        Intent intent = new Intent(RingtoneManager.ACTION_RINGTONE_PICKER);
        intent.putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, RingtoneManager.TYPE_NOTIFICATION);
        intent.putExtra(RingtoneManager.EXTRA_RINGTONE_TITLE, "Select Notification Tone");
        intent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, (Uri) null);
        startActivityForResult(intent, 5); // Request code = 5
    }

    // สร้าง Notification ใช้เสียงที่เลือก
    public void createNotification(View view) {
        NotificationManager mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(MainActivity.this, default_notification_channel_id);

        mBuilder.setContentTitle("Notify Me");
        mBuilder.setContentText("Something important!");
        mBuilder.setSmallIcon(R.drawable.ic_launcher_foreground);
        mBuilder.setAutoCancel(true);

        // ใช้เสียงที่ผู้ใช้เลือก (ถ้ามี)
        if (chosenRingtone != null) {
            mBuilder.setSound(Uri.parse(chosenRingtone));
        }

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            int importance = NotificationManager.IMPORTANCE_HIGH;
            NotificationChannel notificationChannel = new NotificationChannel(
                NOTIFICATION_CHANNEL_ID, "NOTIFICATION_CHANNEL_NAME", importance);
            
            // ตั้งค่าเสียงที่ Channel Level (Android 8.0+)
            if (chosenRingtone != null) {
                notificationChannel.setSound(Uri.parse(chosenRingtone), null);
            }
            
            mBuilder.setChannelId(NOTIFICATION_CHANNEL_ID);
            assert mNotificationManager != null;
            mNotificationManager.createNotificationChannel(notificationChannel);
        }

        assert mNotificationManager != null;
        mNotificationManager.notify((int) System.currentTimeMillis(), mBuilder.build());
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (resultCode == Activity.RESULT_OK && requestCode == 5) {
            Uri uri = data.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI);
            if (uri != null) {
                this.chosenRingtone = uri.toString();
                Toast.makeText(this, "Selected: " + uri.getLastPathSegment(), Toast.LENGTH_SHORT).show();
            } else {
                this.chosenRingtone = null;
                Toast.makeText(this, "Default tone selected", Toast.LENGTH_SHORT).show();
            }
        }
    }
}

ขั้นตอนที่ 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">

    <uses-permission android:name="android.permission.VIBRATE" />

    <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>

2 วิธีการตั้งค่าเสียง Notification

วิธีที่ 1: ตั้งค่าที่ Builder Level (ต่อ Notification)

// ใช้กับ Notification ครั้งนั้นๆ เท่านั้น
mBuilder.setSound(Uri.parse("android.resource://" + getPackageName() + "/" + R.raw.custom_sound));
// หรือ
mBuilder.setSound(ringtoneUri); // จาก RingtonePicker

วิธีที่ 2: ตั้งค่าที่ Channel Level (Android 8.0+ API 26+) - แนะนำ

NotificationChannel channel = new NotificationChannel(CHANNEL_ID, "Name", IMPORTANCE_HIGH);
// ตั้งค่าเสียงสำหรับ Channel นี้ทั้งหมด
channel.setSound(ringtoneUri, null); // AudioAttributes = null ใช้ค่าเริ่มต้น
notificationManager.createNotificationChannel(channel);

// Notification ที่ใช้ Channel นี้จะได้เสียงนี้อัตโนมัติ
mBuilder.setChannelId(CHANNEL_ID);

ประเภทเสียงที่ใช้ได้

แหล่งที่มาตัวอย่าง URIคำอธิบาย
System Ringtonecontent://settings/system/notification_soundเสียงเริ่มต้นของระบบ
RingtonePickercontent://media/internal/audio/media/123เสียงที่ผู้ใช้เลือกจาก Picker
Raw Resourceandroid.resource://com.example.app/raw/notification_soundไฟล์ .mp3/.ogg/.wav ใน res/raw/
File Pathfile:///storage/emulated/0/Download/mysound.mp3ไฟล์ใน External Storage (ต้อง Permission)

ไฟล์เสียงใน res/raw/

  1. สร้างโฟลเดอร์ res/raw/ (New → Android Resource Directory → raw)
  2. วางไฟล์เสียง เช่น notification_sound.mp3 (รองรับ: mp3, ogg, wav)
  3. ใช้ในโค้ด: Uri.parse("android.resource://" + getPackageName() + "/" + R.raw.notification_sound)

AudioAttributes (Android 5.0+ API 21+) - แนะนำ

AudioAttributes audioAttributes = new AudioAttributes.Builder()
    .setUsage(AudioAttributes.USAGE_NOTIFICATION)
    .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
    .build();

// ใช้กับ Channel
channel.setSound(ringtoneUri, audioAttributes);

// หรือใช้กับ Builder (Legacy)
mBuilder.setSound(ringtoneUri, audioAttributes);

ข้อควรระวัง

  • Android 8.0+: ต้องตั้งค่าที่ Channel Level (setSound บน Builder อาจถูกข้าม)
  • Do Not Disturb (DND): ผู้ใช้ตั้งค่า DND อาจบล็อกเสียง ใช้ channel.setBypassDnd(true) สำหรับการแจ้งเตือนสำคัญ
  • โหมด Silent/Vibrate: ระบบจะปิดเสียงอัตโนมัติตามโหมดของโทรศัพท์
  • ขนาดไฟล์: ควรไม่เกิน 1-2 MB สำหรับ Notification Sound
  • ความยาว: ควรสั้น 1-5 วินาที ไม่ควรยาวเกินไป

ทดสอบ

  1. กดปุ่ม "set ringtone" → เลือกเสียงจากรายการ
  2. กดปุ่ม "Create notification" → ตรวจสอบเสียงที่เล่น
  3. ลองตั้งโทรศัพท์เป็น Silent/Vibrate → ทดสอบอีกครั้ง
  4. ทดสอบบนอุปกรณ์จริง (Emulator อาจไม่มีเสียง)