开发一个简易音乐播放器,要求实现: 综合使用Service,BroadCast,ContentProvider等组件实现后台播放。
- 播放和暂停、上一首、下一首、停止;
- 后台播放功能, 按下返回键退出应用后再次打开应用,UI 显示应能与当前的播放状态保持一致;
- 显示正在播放的歌曲名、作者;
- 一首歌曲播放完毕能实现自动播放下一首歌曲,并更新界面,显示相关信息;
提交 MusicService 和 MainActivity,运行结果截图。
评分: 1.基本分,60分,实现基本功能,提交的内容完整,条理清晰,可读性好。 2.上一首、下一首;+20分 3.UI销毁后再次打开应能与当前的播放状态保持一致;+20分
在模拟器中上传音乐:
找到路径:C:\Users\17511\Documents\AndroidStudio\DeviceExplorer\emulator-5554\storage\emulated\legacy\Music
MainActivity.java
package com.example.player;
import android.Manifest;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.ImageButton;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
public static final String CONTROL = "iet.jxufe.cn.android.control";//控制播放、暂停
public static final String UPDATE = "iet.jxufe.cn.android.update";//更新界面显示
// 定义音乐的播放状态,0x11代表没有播放;0x12代表正在播放;0x13代表暂停
int status = 0x11;
//获取界面中显示歌曲标题、作者文本框
TextView title, author;
// 播放/暂停、停止按钮
ImageButton play, stop,next,pre;
ActivityReceiver activityReceiver;
//“启动”服务的intent
Intent MusicServiceIntent;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 获取程序界面中的两个按钮以及两个文本显示框
play = (ImageButton) this.findViewById(R.id.play);
stop = (ImageButton) this.findViewById(R.id.stop);
next = (ImageButton)this.findViewById(R.id.next);
pre = (ImageButton)this.findViewById(R.id.pre);
title = (TextView) findViewById(R.id.title);
author = (TextView) findViewById(R.id.author);
// 为两个按钮的单击事件添加监听器
play.setOnClickListener(this);
stop.setOnClickListener(this);
next.setOnClickListener(this);
pre.setOnClickListener(this);
activityReceiver = new ActivityReceiver();
IntentFilter filter = new IntentFilter(UPDATE);
// 注册BroadcastReceiver
registerReceiver(activityReceiver, filter);
MusicServiceIntent = new Intent(this, MusicService.class);
//判断权限够不够,不够就给
if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(MainActivity.this, new String[]{
Manifest.permission.WRITE_EXTERNAL_STORAGE
}, 1);
} else {
//够了就设置路径等,准备播放
startService(MusicServiceIntent);
}
}
//获取到权限回调方法
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
switch (requestCode) {
case 1:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
startService(MusicServiceIntent);
} else {
Toast.makeText(this, "权限不够获取不到音乐,程序将退出", Toast.LENGTH_SHORT).show();
finish();
}
break;
default:
break;
}
}
public void onClick(View source) {
// 创建Intent
Intent intent = new Intent(CONTROL);
//System.out.println(source.getId());
//System.out.println(source.getId() == R.id.play);
switch (source.getId()) {
// 按下播放/暂停按钮
case R.id.play:
intent.putExtra("control", 1);
Log.d("MusicService","play pressed");
break;
// 按下停止按钮
case R.id.stop:
intent.putExtra("control", 2);
Log.d("MusicService","stop pressed");
break;
case R.id.next:
intent.putExtra("control", 3);
Log.d("MusicService","next pressed");
break;
case R.id.pre:
intent.putExtra("control", 4);
Log.d("MusicService","pre pressed");
break;
}
// 发送广播 ,将被Service组件中的BroadcastReceiver接收到
sendBroadcast(intent);
}
// 自定义的BroadcastReceiver,负责监听从Service传回来的广播
public class ActivityReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
// 获取Intent中的update消息,update代表播放状态,默认为-1
int update = intent.getIntExtra("update", -1);
// 获取Intent中的current消息,current代表当前正在播放的歌曲,默认为-1
String songs_title = "";
songs_title = intent.getStringExtra("songs_title");
String songs_author = "";
songs_author = intent.getStringExtra("songs_author");
if (update >= 0) {
title.setText(songs_title);
author.setText(songs_author);
}
switch (update) {
case 0x11:
play.setImageResource(R.drawable.play);
status = 0x11;
break;
// 控制系统进入播放状态
case 0x12:
// 播放状态下设置使用暂停图标
play.setImageResource(R.drawable.pause);
// 设置当前状态
status = 0x12;
break;
// 控制系统进入暂停状态
case 0x13:
// 暂停状态下设置使用播放图标
play.setImageResource(R.drawable.play);
// 设置当前状态
status = 0x13;
break;
}
}
}
@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(activityReceiver);
}
}
这样就会自动添加权限
MusicService.java
package com.example.player;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.media.MediaPlayer;
import android.os.Environment;
import android.os.IBinder;
import android.util.Log;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class MusicService extends Service {
private static final String TAG = "MusicService";
private List<Map<String,Object>> musicList = new ArrayList<Map<String,Object>>();
private int songsCount = 0;
private ServiceReceiver serviceReceiver;
private MediaPlayer mPlayer;
//当前的状态,0x11 代表没有播放 ;0x12代表 正在播放;0x13代表暂停
private int status = 0x11;
// 记录当前正在播放的音乐
private int current = 0;
public MusicService() {
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
public void onCreate(){
Log.d(TAG,"创建音乐播放服务");
// 创建BroadcastReceiver
serviceReceiver = new ServiceReceiver();
// 创建IntentFilter
IntentFilter filter = new IntentFilter(MainActivity.CONTROL);
registerReceiver(serviceReceiver, filter);
// 创建MediaPlayer
mPlayer = new MediaPlayer();
initSongsData();
// 为MediaPlayer播放完成事件绑定监听器
mPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener(){
public void onCompletion(MediaPlayer mp){
/* current++;
if (current >= songsCount){
current = 0;
}*/
setNextMusic();
/* 发送广播通知Activity更改文本框 */
Intent sendIntent = new Intent(MainActivity.UPDATE);
Map<String,Object> map = musicList.get(current);
status = 0x12;
sendIntent.putExtra("update", status);
sendIntent.putExtra("songs_title",(String)map.get("songs_title"));
sendIntent.putExtra("songs_author",(String)map.get("songs_author"));
// 发送广播 ,将被Activity组件中的BroadcastReceiver接收到
sendBroadcast(sendIntent);
// 准备、并播放音乐
prepareAndPlay((File)map.get("songs_path"));
}
});
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG,"启动音乐播放服务");
//Map<String,Object> map = musicList.get(current);
/* 发送广播通知Activity更改图标、文本框 */
/*Intent sendIntent = new Intent(MainActivity.UPDATE);
sendIntent.putExtra("update", status);
sendIntent.putExtra("songs_title", (String)map.get("songs_title"));
sendIntent.putExtra("songs_author",(String)map.get("songs_author"));
if (status == 0x11)
{
sendIntent.putExtra("songs_title","");
sendIntent.putExtra("songs_author","");
}
// 发送广播 ,将被Activity组件中的BroadcastReceiver接收到
sendBroadcast(sendIntent);*/
return super.onStartCommand(intent, flags, startId);
}
private void setNextMusic(){
current++;
if(current>=songsCount){
current = 0;
}
}
private void setPreMusic(){
current--;
if(current<0){
current = songsCount-1;
}
}
// 初始化MediaPlayer歌曲路径,让MediaPlayer进入到准备状态
private void initSongsData() {
try {
//歌曲路径
Map<String,Object> map = new HashMap<String, Object>();
map.put("songs_title","你是温柔本身");
map.put("songs_author","UN1K");
map.put("songs_path", new File(Environment.getExternalStorageDirectory(), "/Music/a1.mp3"));
musicList.add(map);
map = new HashMap<String, Object>();
map.put("songs_title","白羊");
map.put("songs_author","徐秉龙");
map.put("songs_path", new File(Environment.getExternalStorageDirectory(), "/Music/a2.mp3"));
musicList.add(map);
map = new HashMap<String, Object>();
map.put("songs_title","星空");
map.put("songs_author","Richard Clayderman .天籁村");
map.put("songs_path", new File(Environment.getExternalStorageDirectory(), "/Music/a3.mp3"));
musicList.add(map);
map = new HashMap<String, Object>();
map.put("songs_title","我的一个道姑朋友");
map.put("songs_author","双笙");
map.put("songs_path", new File(Environment.getExternalStorageDirectory(), "/Music/a4.mp3"));
musicList.add(map);
songsCount = musicList.size();
Log.d(TAG,songsCount+"");
//mPlayer.setDataSource(((File)musicList.get(0)).getPath()); // 指定音频文件的路径
//mPlayer.prepare(); // 让MediaPlayer进入到准备状态
} catch (Exception e) {
Log.d(TAG, "设置资源,准备阶段出错");
e.printStackTrace();
}
}
public class ServiceReceiver extends BroadcastReceiver {
public void onReceive(final Context context, Intent intent){
Log.d(TAG,"服务中的广播接收器收到广播");
int control = intent.getIntExtra("control", -1);
Map<String,Object> map = musicList.get(current);
switch (control){
// 播放或暂停
case 1:
// 原来处于没有播放状态
if (status == 0x11){
// 准备、并播放音乐
prepareAndPlay((File) map.get("songs_path"));
status = 0x12;
}
// 原来处于播放状态
else if (status == 0x12){
mPlayer.pause();// 暂停
status = 0x13;// 改变为暂停状态
}
// 原来处于暂停状态
else if (status == 0x13){
mPlayer.start();// 播放
status = 0x12;// 改变状态
}
break;
// 停止声音
case 2:
// 如果原来正在播放或暂停
if (status == 0x12 || status == 0x13){
current = 0;
//mPlayer.reset();
mPlayer.stop();// 停止播放
status = 0x11;
}
break;
case 3:
setNextMusic();
status = 0x12;
map = musicList.get(current);
prepareAndPlay((File)map.get("songs_path"));
break;
case 4:
// 上一首
setPreMusic();
status = 0x12;
map = musicList.get(current);
prepareAndPlay((File) map.get("songs_path"));
break;
}
/*/* 发送广播通知Activity更改图标、文本框 */
Intent sendIntent = new Intent(MainActivity.UPDATE);
sendIntent.putExtra("update", status);
sendIntent.putExtra("songs_title", (String)map.get("songs_title"));
sendIntent.putExtra("songs_author",(String)map.get("songs_author"));
if (status == 0x11)
{
sendIntent.putExtra("songs_title","");
sendIntent.putExtra("songs_author","");
}
// 发送广播 ,将被Activity组件中的BroadcastReceiver接收到
sendBroadcast(sendIntent);
}
}
private void prepareAndPlay(File songsPath){
try{
mPlayer.reset();
//使用MediaPlayer加载指定的声音文件。
mPlayer.setDataSource(songsPath.getPath());
mPlayer.prepare();// 准备声音
mPlayer.start();// 播放
}
catch (IOException e){
e.printStackTrace();
}
}
@Override
public void onDestroy() {
super.onDestroy();
unregisterReceiver(serviceReceiver);
}
}
activity_main.xml
<?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:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/bg"
android:orientation="vertical"
tools:context=".MainActivity">
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="horizontal">
<ImageButton
android:id="@+id/pre"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/selector_btn"
android:src="@drawable/previous_button" />
<ImageButton
android:id="@+id/stop"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/selector_btn"
android:src="@drawable/stop" />
<ImageButton
android:id="@+id/play"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/selector_btn"
android:src="@drawable/play" />
<ImageButton
android:id="@+id/next"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/selector_btn"
android:src="@drawable/next_button" />
</LinearLayout>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textColor="#ffffff"
android:layout_gravity="fill_vertical"
android:textSize="20sp" />
<TextView
android:id="@+id/author"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_gravity="fill_vertical"
android:textColor="#ffffff"
android:textSize="18sp" />
</LinearLayout>
</LinearLayout>
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.player">
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<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">
<service
android:name=".MusicService"
android:enabled="true"
android:exported="true"></service>
<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>
初始界面:
点击播放:
点击暂停:
点击下一首:
点击停止: