Java-Spring实战指南(三十四)Android Service实现后台音乐播放功能
- 前言
- 前置准备
- 一、Service核心概念
-
- [1.1 什么是Service?](#1.1 什么是Service?)
- [1.2 Service生命周期(重点)](#1.2 Service生命周期(重点))
- [1.3 项目结构总览](#1.3 项目结构总览)
- 二、代码实现
-
- [2.1 第一步:添加音乐资源](#2.1 第一步:添加音乐资源)
- [2.2 第二步:编写Service核心类(MusicService.java)](#2.2 第二步:编写Service核心类(MusicService.java))
- [2.3 第三步:编写界面布局(activity_service.xml)](#2.3 第三步:编写界面布局(activity_service.xml))
- [2.4 第四步:编写Activity交互逻辑(ServiceActivity.java)](#2.4 第四步:编写Activity交互逻辑(ServiceActivity.java))
- [2.5 第五步:注册组件(AndroidManifest.xml)](#2.5 第五步:注册组件(AndroidManifest.xml))
- 三、运行测试
前言
上一篇我们完成了SSM+Android跨端登录注册的综合实战,掌握了前后端数据交互的核心逻辑。本节课将聚焦Android另一个核心组件------Service(服务),它是运行在后台的"无界面组件",适合执行长时间运行的任务(如音乐播放、文件下载、网络请求)。
本文将基于 Android Studio 2025.1.4 + 模拟器Android 14 环境,手把手实现"后台音乐播放"功能:通过Service管理音乐播放/暂停逻辑,Activity作为界面交互入口,让你彻底理解Service的生命周期、启动/停止方式以及组件间的通信逻辑。
我的个人主页,欢迎阅读其他文章
https://blog.csdn.net/2402_83322742?spm=1011.2415.3001.5343我的Java-Spring入门指南专栏
欢迎指出不足
https://blog.csdn.net/2402_83322742/category_13040333.html?spm=1001.2014.3001.5482

前置准备
开始前确保以下环境和资源就绪:
- 开发工具:Android Studio 2025.1.4
- 模拟器/真机:Android 14(API 34)
- 音乐资源 :准备一首MP3格式音乐,命名为
music.mp3(后续放入res/raw文件夹) - 核心知识点:了解Android组件基础、Intent通信(前序博客已覆盖)
一、Service核心概念
1.1 什么是Service?
Service是Android四大组件之一,运行在主线程后台(非独立进程),无可视化界面,适合执行不需要用户交互的长时间任务。
| Service核心特性 | 说明 | 类比场景 |
|---|---|---|
| 无界面 | 不占用屏幕空间,后台运行 | 电脑后台的音乐播放器进程 |
| 生命周期长 | 即使Activity销毁,Service可继续运行 | 关闭视频软件窗口,背景音乐仍播放 |
| 主线程运行 | 默认在主线程执行,耗时操作需手动开子线程 | 需配合Thread/AsyncTask处理耗时任务 |
1.2 Service生命周期(重点)
本次实战使用"启动式Service"(startService()启动,stopService()停止),核心生命周期方法如下:
onCreate():Service首次创建时调用(仅执行1次),用于初始化资源(如创建MediaPlayer);onStartCommand():每次调用startService()时触发,用于执行具体业务逻辑(如播放音乐);onDestroy():Service销毁时调用(执行stopService()或系统回收),用于释放资源(如停止播放、释放MediaPlayer)。
1.3 项目结构总览

com.example.ch9service
├── MusicService.java // 核心Service:管理音乐播放/暂停/释放
├── ServiceActivity.java // 界面Activity:提供播放/暂停按钮交互
├── res
│ ├── raw // 音乐资源文件夹(存放music.mp3)
│ │ └── music.mp3
│ ├── layout
│ │ └── activity_service.xml // 界面布局(仅1个按钮)
│ └── values
│ └── strings.xml
└── AndroidManifest.xml // 清单文件:注册Service和Activity
二、代码实现
2.1 第一步:添加音乐资源
- 在
res文件夹下新建raw文件夹(右键res→New→Android Resource Directory→Resource type选raw); - 将MP3音乐文件放入
raw文件夹,命名为music.mp3(注意:文件名只能包含字母、数字和下划线,不能有中文)。
2.2 第二步:编写Service核心类(MusicService.java)
MusicService负责音乐播放的核心逻辑:初始化MediaPlayer、播放、停止、释放资源,通过静态变量ispaly记录播放状态。
java
package com.example.ch9service;
import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.IBinder;
// 后台音乐播放Service
public class MusicService extends Service {
private MediaPlayer player; // 音乐播放器实例
public static boolean ispaly = false; // 播放状态标记(静态变量,供Activity访问)
public MusicService() {
// 必须实现的构造方法(无参)
}
@Override
public IBinder onBind(Intent intent) {
// 启动式Service无需绑定,返回null即可(若为绑定式Service需实现)
throw new UnsupportedOperationException("Not yet implemented");
}
// Service创建时调用(仅1次):初始化MediaPlayer
@Override
public void onCreate() {
super.onCreate();
// 创建MediaPlayer实例,加载raw文件夹中的音乐资源
player = MediaPlayer.create(this, R.raw.music);
// 设置音乐循环播放(可选,根据需求调整)
player.setLooping(true);
}
// 每次调用startService()时触发:执行播放逻辑
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// 若未在播放,则启动播放
if (!player.isPlaying()) {
player.start(); // 开始播放音乐
ispaly = player.isPlaying(); // 更新播放状态为true
}
// 返回值:Service被系统回收后是否重建,START_STICKY表示重建
return super.onStartCommand(intent, flags, startId);
}
// Service销毁时调用:释放资源(关键,避免内存泄漏)
@Override
public void onDestroy() {
super.onDestroy();
if (player != null) {
player.stop(); // 停止播放
ispaly = player.isPlaying(); // 更新播放状态为false
player.release(); // 释放MediaPlayer资源
player = null; // 置空,便于GC回收
}
}
}
2.3 第三步:编写界面布局(activity_service.xml)
布局仅包含1个按钮,用于切换"播放"和"暂停"状态,采用ConstraintLayout居中布局。
xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ServiceActivity">
<!-- 播放/暂停切换按钮 -->
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="播放音乐"
android:textSize="18sp"
android:paddingHorizontal="30dp"
android:paddingVertical="10dp"
<!-- 约束布局:水平+垂直居中 -->
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
2.4 第四步:编写Activity交互逻辑(ServiceActivity.java)
ServiceActivity作为界面入口,通过按钮点击事件启动/停止MusicService,并根据ispaly状态切换按钮文本。
java
package com.example.ch9service;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
public class ServiceActivity extends AppCompatActivity {
private Button playBtn; // 播放/暂停按钮
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
EdgeToEdge.enable(this); // 启用沉浸式布局
setContentView(R.layout.activity_service);
// 适配系统状态栏(避免按钮被遮挡)
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
return insets;
});
// 绑定按钮控件
playBtn = findViewById(R.id.button);
// 设置按钮点击事件
playBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 创建Intent,指定目标Service
Intent intent = new Intent(ServiceActivity.this, MusicService.class);
// 根据播放状态切换:未播放→启动Service(播放);已播放→停止Service(暂停)
if (!MusicService.ispaly) {
startService(intent); // 启动Service,触发onStartCommand()
playBtn.setText("暂停音乐"); // 切换按钮文本
} else {
stopService(intent); // 停止Service,触发onDestroy()
playBtn.setText("播放音乐"); // 切换按钮文本
}
}
});
}
}
2.5 第五步:注册组件(AndroidManifest.xml)
Service和Activity都需在清单文件中注册,否则无法使用。
xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<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/Theme.MyApplication">
<!-- 注册Service:android:exported="true"允许外部启动(此处为应用内部使用,也可设为false) -->
<service
android:name=".MusicService"
android:enabled="true"
android:exported="true"></service>
<!-- 注册Activity(启动页) -->
<activity
android:name=".ServiceActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
三、运行测试

我的个人主页,欢迎来阅读我的其他文章
https://blog.csdn.net/2402_83322742?spm=1011.2415.3001.5343我的Java-Spring入门指南专栏
欢迎来阅读指出不足
https://blog.csdn.net/2402_83322742/category_13040333.html?spm=1001.2014.3001.5482
|--------------------|
| 非常感谢您的阅读,喜欢的话记得三连哦 |
