1 实验名称
音乐播放器
2 实验目的
掌握使用Service启动服务的方法,掌握BroadcastReceiver广播传递机制的实现,利用Activity、Service和BroadcastReceiver实现一个音乐播放器APP。
3 实验源代码
布局文件代码:
java
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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="wrap_content"
android:orientation="horizontal"
android:background="@drawable/bg"
tools:context=".MainActivity">
<ImageButton
android:id="@+id/stopImageBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/stop"
/>
<ImageButton
android:id="@+id/playImageBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/play"
/>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
>
<TextView
android:id="@+id/songNameTV"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#ffffff"
android:textSize="24sp"
android:text="歌曲名"
android:layout_weight="2"
/>
<TextView
android:id="@+id/singerNameTV"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#ffffff"
android:textSize="20sp"
android:text="歌手名"
android:layout_weight="1"
/>
</LinearLayout>
</LinearLayout>
java代码:
(1)MainActivity
java
package com.example.musicplayertest;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageButton;
import android.widget.TextView;
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 MainActivity extends AppCompatActivity {
private ImageButton stopImageBtn = null;
private ImageButton playImageBtn = null;
private TextView songNameTV = null;
private TextView singerNameTV = null;
private ServiceReceiver serviceReceiver = null;
private IntentFilter intentFilter= null;
private boolean isPlaying = false;//定义一个反映MusicService播放状态的变量
//定义存放歌曲名的数组
private String []songNames = new String[]{"若思念便思念","就在江湖之上","山外"};
//定义存放歌手名的数组
private String []singerNames = new String[]{"周深","刘宇宁","张远"};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
stopImageBtn = findViewById(R.id.stopImageBtn);
playImageBtn = findViewById(R.id.playImageBtn);
songNameTV = findViewById(R.id.songNameTV);
singerNameTV = findViewById(R.id.singerNameTV);
init();
playImageBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent("cn.edu.nuc.mainactivity");
//控制指令:1表示播放指令,2表示暂停指令,3表示停止指令
if (isPlaying){//如果isPlaying为真,说明后台正在播放音乐
intent.putExtra("control",2);//封装暂停指令
playImageBtn.setImageResource(R.drawable.play);//更新为播放按钮图片
isPlaying = false;
}else {//后台播放状态是暂停或停止状态
intent.putExtra("control",1);//封装播放指令
playImageBtn.setImageResource(R.drawable.pause);
isPlaying = true;
}
sendBroadcast(intent);//发送带有过滤条件和控制指令的广播
}
});
stopImageBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent("cn.edu.nuc.mainactivity");
intent.putExtra("control",3);//封装停止指令
playImageBtn.setImageResource(R.drawable.play);//更新为播放按钮图片
isPlaying = false;
sendBroadcast(intent);
}
});
}
private void init(){
//启动MusicService
Intent intent = new Intent(MainActivity.this, MusicService.class);
startService(intent);//启动MusicService
//创建广播接收器对象
serviceReceiver = new ServiceReceiver();
intentFilter = new IntentFilter("cn.edu.nuc.musicservice");
//动态注册广播接收器
registerReceiver(serviceReceiver,intentFilter);
}
//定义用于接受MusicService发送的广播接收器类
private class ServiceReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
int status = intent.getIntExtra("status",-1);
int current = intent.getIntExtra("current",-1);
//根据后台播放状态更新播放按钮的图片
switch (status){
//定义当前音乐播放状态的变量,0x11表示停止状态,0x12表示正在播放状态,0x13表示暂停状态
case 0x11:
playImageBtn.setImageResource(R.drawable.play);
break;
case 0x12:
playImageBtn.setImageResource(R.drawable.pause);
break;
case 0x13:
playImageBtn.setImageResource(R.drawable.play);
break;
default:break;
}
//在播放器界面对应的文本框中更新当前正在播放的歌曲信息
if (current>=0){
songNameTV.setText(songNames[current]);
singerNameTV.setText(singerNames[current]);
}
}
}
}
(2)MusicService
java
package com.example.musicplayertest;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.AssetFileDescriptor;
import android.content.res.AssetManager;
import android.media.MediaPlayer;
import android.os.IBinder;
import java.io.IOException;
public class MusicService extends Service {
//定义一个媒体播放器
private MediaPlayer mediaPlayer = null;
//定义一个广播接收器
private ActivityReceiver activityReceiver = null;
//定义广播过滤器
private IntentFilter intentFilter = null;
//定义资源管理器
private AssetManager assetManager = null;
//将歌曲文件信息存放到数组中
String []musics = new String[]{"life.mp3","road.mp3","star.mp3"};
//定义一个存放当前正在播放的音乐的索引值变量
int current = 0;
//定义当前音乐播放状态的变量,0x11表示停止状态,0x12表示正在播放状态,0x13表示暂停状态
int status = 0x11;
public MusicService() {
}
@Override
public void onCreate() {
super.onCreate();
activityReceiver =new ActivityReceiver();//创建广播接收器对象
intentFilter = new IntentFilter("cn.edu.nuc.mainactivity");
registerReceiver(activityReceiver,intentFilter);//动态注册广播接收器
mediaPlayer = new MediaPlayer();
//给mediaPlayer添加播放完一首歌后的事件监听处理,实现自动播放下一首
mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
current++;
if (current>=3){
current = 0;
}
Intent sendIntent = new Intent("cn.edu.nuc.musicservice");
sendIntent.putExtra("current",current);
sendBroadcast(sendIntent);
prepareAndPlay(musics[current]);
}
});
assetManager = getAssets();//创建资源管理器对象
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
//定义用于接受MainActivity发送的广播的广播接收器类
private class ActivityReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
//从MainActivity发送过来的广播中解析出控制指令
int control = intent.getIntExtra("control",-1);
//控制指令:1表示播放指令,2表示暂停指令,3表示停止指令
//定义当前音乐播放状态的变量,0x11表示停止状态,0x12表示正在播放状态,0x13表示暂停状态
switch (control){
case 1:
if (status == 0x11){
prepareAndPlay(musics[current]);
status = 0x12;
} else if (status == 0x12) {
mediaPlayer.pause();
status = 0x13;
} else if (status == 0x13) {
mediaPlayer.start();
status = 0x12;
}
break;
case 2:
//暂停音乐播放
mediaPlayer.pause();
status = 0x13;
break;
case 3:
//停止音乐播放
mediaPlayer.stop();
status = 0x11;
break;
default:break;
}
//向MainActivity发送含有当前播放状态和歌曲索引值的广播
Intent sendIntent = new Intent("cn.edu.nuc.musicservice");
sendIntent.putExtra("status",status);
sendIntent.putExtra("current",current);
sendBroadcast(sendIntent);
}
}
//定义初始化音乐播放的方法
private void prepareAndPlay(String music){
try {
//创建音乐文件的一个资源文件描述符
AssetFileDescriptor assetFileDescriptor = assetManager.openFd(music);
mediaPlayer.reset();//重置媒体播放器
mediaPlayer.setDataSource(assetFileDescriptor.getFileDescriptor(),
assetFileDescriptor.getStartOffset(),
assetFileDescriptor.getLength());//将要播放的音乐文件设置为媒体播放器的播放资源
mediaPlayer.prepare();//准备声音
mediaPlayer.start();//播放音乐
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
4 实验运行结果图
5 实验总结
第一步,写布局文件。主要是两个图片按钮和两个文本框,图像按钮分别是暂停和播放;文本框分别是歌曲名和歌手名。
写完布局文件开始写Java代码。设置控制指令,1表示播放指令,2表示暂停指令,3表示停止指令;再定义当前音乐播放状态的变量,0x11表示停止状态,0x12表示正在播放状态,0x13表示暂停状态;再分别定义存放歌曲名和歌手名的数组,将歌曲文件信息存放到数组中。
分别定义一个媒体播放器、广播接收器、广播过滤器、资源管理器和一个存放当前正在播放的音乐的索引值变量。关于广播接收器,先创建广播接收器对象,动态注册广播接收器,给媒体播放器添加播放完一首歌后的事件监听处理,实现自动播放下一首。关于广播接收器,定义用于接收发送过来的广播的广播接收器类,从发送过来的广播中解析出指令,向其发送含有当前播放状态和歌曲索引值的广播。关于音乐播放,定义一个初始化音乐播放的方法,创建音乐文件的一个资源文件描述符,重置媒体播放器,将要播放的音乐文件设置位媒体播放器的播放资源,准备声音播放音乐。