Giới thiệu
Bài viết này hướng dẫn cách phát nhạc nền (background music) trong ứng dụng Android bằng cách sử dụng Service và MediaPlayer. Nhạc sẽ tiếp tục phát ngay cả khi người dùng thoát khỏi Activity (nhấn Home, mở app khác) - phù hợp cho game, app nghe nhạc, meditation.
Các bước thực hiện
Bước 1: Tạo dự án mới
Mở Android Studio, chọn File → New Project và điền thông tin cần thiết.
Bước 2: Layout chính (res/layout/activity_main.xml)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal"
android:orientation="vertical"
android:padding="16dp">
<Button
android:id="@+id/btnPlay"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Phát nhạc nền" />
<Button
android:id="@+id/btnStop"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="Dừng nhạc" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:text="Nhạc đang phát trong background"
android:textSize="16sp"
android:textStyle="bold" />
</LinearLayout>
Bước 3: Tạo file nhạc
Tạo thư mục res/raw/ (chuột phải res → New → Android Resource Directory → Type: raw) và copy file nhạc (ví dụ: background_music.mp3) vào đó.
Bước 4: Tạo BackgroundSoundService (BackgroundSoundService.java)
import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.IBinder;
import android.widget.Toast;
import androidx.annotation.Nullable;
public class BackgroundSoundService extends Service {
private MediaPlayer mediaPlayer;
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null; // Không hỗ trợ binding
}
@Override
public void onCreate() {
super.onCreate();
// Tạo MediaPlayer từ raw resource
mediaPlayer = MediaPlayer.create(this, R.raw.background_music);
if (mediaPlayer != null) {
mediaPlayer.setLooping(true); // Lặp lại liên tục
mediaPlayer.setVolume(1.0f, 1.0f); // Âm lượng max (0.0f - 1.0f)
}
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (mediaPlayer != null && !mediaPlayer.isPlaying()) {
mediaPlayer.start();
Toast.makeText(this, "Đang phát nhạc nền...", Toast.LENGTH_SHORT).show();
}
// START_STICKY: Hệ thống sẽ restart service nếu bị kill do thiếu bộ nhớ
return START_STICKY;
}
@Override
public void onDestroy() {
super.onDestroy();
if (mediaPlayer != null) {
mediaPlayer.stop();
mediaPlayer.release();
mediaPlayer = null;
}
}
}
Bước 5: Activity chính (MainActivity.java)
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
public class MainActivity extends AppCompatActivity {
private Button btnPlay, btnStop;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnPlay = findViewById(R.id.btnPlay);
btnStop = findViewById(R.id.btnStop);
btnPlay.setOnClickListener(v -> startBackgroundMusic());
btnStop.setOnClickListener(v -> stopBackgroundMusic());
}
private void startBackgroundMusic() {
Intent intent = new Intent(this, BackgroundSoundService.class);
startService(intent);
}
private void stopBackgroundMusic() {
Intent intent = new Intent(this, BackgroundSoundService.class);
stopService(intent);
}
}
Bước 6: Khai báo Service trong Manifest (androidManifest.xml)
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="https://schemas.android.com/apk/res/android"
package="app.com.sample">
<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>
</intent-filter>
</activity>
<!-- KHAI BÁO SERVICE -->
<service
android:name=".BackgroundSoundService"
android:exported="false"
android:foregroundServiceType="mediaPlayback" />
</application>
</manifest>
Chạy ứng dụng
Kết nối thiết bị, nhấn Run. Nhấn "Phát nhạc nền" -> nhạc phát. Nhấn Home, mở app khác -> nhạc vẫn phát. Quay lại app, nhấn "Dừng nhạc" -> nhạc dừng.
Quan trọng: Foreground Service (Android 8.0+ / API 26+)
Từ Android 8.0, Service chạy background bị hạn chế. Phát nhạc nền bắt buộc dùng Foreground Service với Notification để tránh bị hệ thống kill.
Cập nhật BackgroundSoundService cho Foreground Service
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.Build;
import android.os.IBinder;
import androidx.annotation.Nullable;
import androidx.core.app.NotificationCompat;
public class BackgroundSoundService extends Service {
private static final String CHANNEL_ID = "MusicPlaybackChannel";
private static final int NOTIFICATION_ID = 101;
private MediaPlayer mediaPlayer;
@Override
public void onCreate() {
super.onCreate();
createNotificationChannel();
mediaPlayer = MediaPlayer.create(this, R.raw.background_music);
if (mediaPlayer != null) {
mediaPlayer.setLooping(true);
mediaPlayer.setVolume(1.0f, 1.0f);
}
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (mediaPlayer != null && !mediaPlayer.isPlaying()) {
mediaPlayer.start();
}
// Tạo notification cho foreground service
Notification notification = createNotification();
// Start foreground (API 26+)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForeground(NOTIFICATION_ID, notification,
ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK);
} else {
startForeground(NOTIFICATION_ID, notification);
}
return START_STICKY;
}
private void createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(
CHANNEL_ID, "Music Playback", NotificationManager.IMPORTANCE_LOW
);
channel.setDescription("Điều khiển phát nhạc nền");
NotificationManager manager = getSystemService(NotificationManager.class);
manager.createNotificationChannel(channel);
}
}
private Notification createNotification() {
Intent stopIntent = new Intent(this, BackgroundSoundService.class);
stopIntent.setAction("STOP");
PendingIntent stopPendingIntent = PendingIntent.getService(
this, 0, stopIntent, PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_CANCEL_CURRENT
);
return new NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("Đang phát nhạc")
.setContentText("Nhấn để dừng")
.setSmallIcon(R.drawable.ic_music_note)
.addAction(R.drawable.ic_stop, "Dừng", stopPendingIntent)
.setOngoing(true)
.setCategory(NotificationCompat.CATEGORY_TRANSPORT)
.build();
}
@Override
public void onDestroy() {
super.onDestroy();
if (mediaPlayer != null) {
mediaPlayer.stop();
mediaPlayer.release();
mediaPlayer = null;
}
stopForeground(true);
}
}
Quyền cần thiết (Android 9+ / API 28+)
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" /> <!-- API 29+ -->
Thư viện hiện đại: Media3 / ExoPlayer
Đối với ứng dụng phát nhạc chuyên nghiệp, nên dùng Media3 (ExoPlayer) với MediaSessionService - hỗ trợ lock screen controls, Bluetooth, Assistant, Cast, v.v.
implementation "androidx.media3:media3-session:1.4.0" implementation "androidx.media3:media3-exoplayer:1.4.0" // MediaSessionService tự xử lý foreground, notification, media controls
Lưu ý quan trọng
- Luôn dùng Foreground Service cho phát nhạc nền từ API 26+.
android:exported="false"cho service chỉ dùng nội bộ app.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK(API 29+) bắt buộc khai báo.- Xử lý audio focus:
AudioManager.requestAudioFocus()để tạm dừng khi có cuộc gọi, alarm... - MediaPlayer cần
release()kịp thời tránh leak native memory. - Test trên Android 14+ (foreground service behavior thay đổi).