简易音乐播放器(Mediaplayer+Broadcast+Service)可拖动进度条
实现效果图以及功能说明
功能说明 : 支持
① 读取sdcard目录下的歌曲,列表展示
② 点击列表切换歌曲,可以切换上一首,下一首,暂停,重置音乐
③ 可以选择播放模式,按照按钮顺序分别是单曲循环,随机播放,列表循环,由于实现逻辑,需要等到当前歌曲结束才能生效
④ 可以拖拽进度条更新进度
⑤自动播放下一首,打开自动播放第一首,后台播放,重新进入状态一致
存在的问题:MainActivity活动销毁启动后台服务,但是无法做到清空后台之后暂停音乐服务(简单来说后台全部清空音乐还是继续播放)
效果图
效果动图
实现框架
实现思路
① 构建一个包装类用来保存歌曲信息、作者以及歌曲路径,作为列表的填充对象
② MainActivity 作为填充文本和图片的活动,MusicService作为更改mediaplayer的类,二者之间采用广播的形式进行数据更新
③ TextAdapter继承BaseAdapter,在原来的基础之上给每一个数据项添加监听,作为信息更改,相应的需要将对应的歌曲序号广播,传回MusicService的广播接收器,进行数据更新
④ 由于偷懒,歌曲的原始数据我在MainActivity和MusicService都获取了一次,有需要可以自己实现数据共享
⑤ 进度条以及按钮点击和列表项点击均是传回control信号给MusicService进行更新,然后MusicService传回update信号要求MainActivity更新歌曲文本
⑥ 需要开启一个线程来不断刷新进度条
实现步骤
① 进入manifest.xml 之中添加权限和服务
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<service
android:name=".MusicService"
android:enabled="true"
android:exported="true" />
② 设置列表子项布局
item.xml 两个文本框分别显示歌曲名称以及作者,最后一个文本框作为分割
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="5dp"
android:id="@+id/ll1"
android:orientation="vertical">
<TextView
android:id="@+id/txt1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="18sp"
/>
<TextView
android:id="@+id/txt2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="18sp"
/>
<TextView
android:id="@+id/txt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="18sp"
/>
</LinearLayout>
③ 主页面添加进度条,列表以及七个按钮 其中进度条进度点换成了一张icon
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="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:textColor="#276893"
android:textSize="20sp" />
<TextView
android:id="@+id/author"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:textColor="#4a6f5d"
android:textSize="18sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:orientation="horizontal">
<TextView
android:id="@+id/currenPosition"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="TextView" />
<SeekBar
android:id="@+id/seekBar"
android:layout_width="0dp"
android:thumb="@drawable/pig"
android:thumbOffset="0dp"
android:layout_height="wrap_content"
android:layout_weight="6" />
<TextView
android:id="@+id/duration"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_weight="1"
android:text="TextView" />
</LinearLayout>
<ListView
android:id="@+id/list"
android:layout_width="match_parent"
android:layout_height="450dp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<ImageButton
android:id="@+id/previous"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="@drawable/selector_btn"
android:src="@drawable/previous_button" />
<ImageButton
android:id="@+id/play"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="@drawable/selector_btn"
android:src="@drawable/play_button" />
<ImageButton
android:id="@+id/next"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="@drawable/selector_btn"
android:src="@drawable/next_button" />
<ImageButton
android:id="@+id/stop"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:background="@drawable/selector_btn"
android:src="@drawable/stop" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<ImageButton
android:id="@+id/loop"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="@drawable/selector_btn"
android:src="@drawable/loop" />
<ImageButton
android:id="@+id/random"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="@drawable/selector_btn"
android:src="@drawable/random" />
<ImageButton
android:id="@+id/all"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:background="@drawable/selector_btn"
android:src="@drawable/loop_all" />
</LinearLayout>
</LinearLayout>
④ 编写对应的方法即可
MainActivity.java
package com.example.musicdemo;
import android.Manifest;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.os.Bundle;
import android.provider.MediaStore;
import android.util.Log;
import android.view.View;
import android.widget.ImageButton;
import android.widget.ListView;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
// 播放暂停
public static final String CONTROL = "com.example.musicdemo.control";//控制播放、暂停
public static final String UPDATE = "com.example.musicdemo.update";//更新界面显示
// 定义音乐的播放状态,0x11代表没有播放;0x12代表正在播放;0x13代表暂停
final private int NOPLAY = 0x11;
final private int PLAYING = 0x12;
final private int PAUSE = 0x13;
// 记录初始的状态
int status = NOPLAY;
//定义UI界面上的各按钮按下时所代表的控制信号
final private int PLAY_OR_PAUSE = 1;
final private int STOP = 2;
final private int NEXT = 3;
final private int PREVIOUS = 4;
final private int LOOP = 5;
final private int RANDOM = 6;
final private int LOOP_ALL = 7;
final private int PROGRESS = 8;
// 获取界面中显示歌曲标题、作者文本框
TextView title, author;
// 播放/暂停、停止按钮
ImageButton play, stop, next, previous;
// 广播接收类
MainActivity.ActivityReceiver activityReceiver;
// 显示音乐播放时长的标签
private TextView tvDuration;
private TextView tvCurrentPosition;
private SeekBar sbMusicProgress;
private ImageButton imageButton1,imageButton2,imageButton3;
// 进度条下面的当前进度文字,将毫秒化为m:ss格式
private SimpleDateFormat time = new SimpleDateFormat("mm:ss");
// 歌曲列表
private ListView AlbumList;
//“启动”服务的intent
Intent MusicServiceIntent;
// 信息列表
List<Messageinfo>info;
@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);
// 上一首组件
previous = (ImageButton) this.findViewById(R.id.previous);
// 总进度组件
tvDuration = findViewById(R.id.duration);
// 当前进度组件
tvCurrentPosition = (TextView) findViewById(R.id.currenPosition);
// 进度条组件
sbMusicProgress = (SeekBar) findViewById(R.id.seekBar);
// 歌曲名称组件
title = (TextView) findViewById(R.id.title);
// 歌曲作者组件
author = (TextView) findViewById(R.id.author);
// 单曲循环组件
imageButton1 = (ImageButton) findViewById(R.id.loop);
// 随机播放组件
imageButton2 = (ImageButton) findViewById(R.id.random);
// 列表循环组件
imageButton3 = (ImageButton) findViewById(R.id.all);
// 列表组件
AlbumList = (ListView)findViewById(R.id.list);
// 7个按钮添加监听器
play.setOnClickListener(this);
stop.setOnClickListener(this);
next.setOnClickListener(this);
previous.setOnClickListener(this);
imageButton1.setOnClickListener(this);
imageButton2.setOnClickListener(this);
imageButton3.setOnClickListener(this);
// 为MainActivity注册BroadcastReceiver 注册信息 UPDATE代表监听的信号源
activityReceiver = new MainActivity.ActivityReceiver();
IntentFilter filter = new IntentFilter(UPDATE);
// 注册BroadcastReceiver
registerReceiver(activityReceiver, filter);
// 添加服务项
MusicServiceIntent = new Intent(this, MusicService.class);
// 初始化原始歌曲数据
info = new ArrayList<Messageinfo>();
initSongsData();
// 添加适配器
TextAdapter adapter = new TextAdapter(info,this);
AlbumList.setAdapter(adapter);
// 判断启动权限,权限不够进行申请
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);
}
// 进度条添加监听
sbMusicProgress.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
// 查看当前进度是否变化
if (b) {
// 创建 Intent
Intent intent = new Intent(CONTROL);
// 设置广播频道:用户修改播放进度
intent.putExtra("control", PROGRESS);
// 更新进度值
intent.putExtra("progress",i);
sendBroadcast(intent);
}
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
}
// 初始化MediaPlayer歌曲路径,让MediaPlayer进入到准备状态
private void initSongsData() {
// 查询数据库
Cursor cursor = getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,null,null,null,null);
while (cursor.moveToNext())
{
// 获取所有歌曲的名称、作者、以及播放路径
String title = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DISPLAY_NAME));
String author = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ARTIST));
String Data = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA));
Messageinfo messageinfo = new Messageinfo(title,author,new File(Data));
// 添加到封装类
info.add(messageinfo);
}
}
@Override
public void onClick(View source) {
// 传递给Musicservice信号,要求其改变歌曲,随之Service会传回信息要求Main这边更新图片和文本信息
Intent intent = new Intent(CONTROL);
switch (source.getId()) {
// 开始播放
case R.id.play:
intent.putExtra("control", PLAY_OR_PAUSE);
break;
// 暂停播放
case R.id.stop:
intent.putExtra("control", STOP);
break;
// 下一首
case R.id.next:
intent.putExtra("control",NEXT);
break;
// 上一首
case R.id.previous:
intent.putExtra("control",PREVIOUS);
break;
// 单曲循环
case R.id.loop:
intent.putExtra("control",LOOP);
break;
// 随机播放
case R.id.random:
intent.putExtra("control",RANDOM);
break;
// 顺序循环
case R.id.all:
intent.putExtra("control",LOOP_ALL);
break;
}
// 发送广播 ,将被Service组件中的BroadcastReceiver接收到
sendBroadcast(intent);
}
// 自定义的BroadcastReceiver,负责进行进度条等文本信息以及图片信息的更新
public class ActivityReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
// 获取Intent中的update消息,update代表播放状态,默认为-1
int update = intent.getIntExtra("update", -1);
// 当前时长
int current_position = intent.getIntExtra("current_position", -1);
// 总时长
int duration = intent.getIntExtra("songs_duration", -1);
if(current_position != -1)// 说明此时只需要更新进度条
{
tvCurrentPosition.setText(time.format(current_position));
// 设置播放拖拽条的进度值,进度值的百分比 current_position当前进度 duration 总时长
sbMusicProgress.setProgress(current_position* 100/duration );
}
else // 需要更新其它信息
{
// 文本框更新标题以及作者
String songs_title = intent.getStringExtra("songs_title");
String songs_author = intent.getStringExtra("songs_author");
title.setText(songs_title);
author.setText(songs_author);
// 更新当前播放时长 转化为mm:ss的格式
tvDuration.setText(time.format(duration));
switch (update) {
// 未播放状态
case NOPLAY:
// 未播放状态下设置使用播放图标
play.setImageResource(R.drawable.play);
// 设置当前状态
status = NOPLAY;
// 播放时长重置
tvCurrentPosition.setText("00:00");
// 进度清零
sbMusicProgress.setProgress(0);
break;
// 进入播放状态
case PLAYING:
// 播放状态下设置使用暂停图标
play.setImageResource(R.drawable.pause);
// 设置当前状态
status = PLAYING;
break;
// 控制播放器进入暂停状态
case PAUSE:
// 暂停状态下设置使用播放图标
play.setImageResource(R.drawable.play);
// 设置当前状态
status = PAUSE;
break;
}
}
}
}
//获取到权限回调方法
@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;
}
}
@Override
protected void onDestroy() {
super.onDestroy();
// 解除注册
unregisterReceiver(activityReceiver);
// 切换到服务项,后台进行运行
MusicServiceIntent = new Intent(this, MusicService.class);
}
}
TextAdapter.java
package com.example.musicdemo;
import android.app.Activity;
import android.app.ActivityManager;
import android.content.Context;
import android.content.Intent;
import android.os.RemoteException;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import java.util.HashMap;
import java.util.List;
import java.util.zip.Inflater;
public class TextAdapter extends BaseAdapter {
public static final String CONTROL = "com.example.musicdemo.control";//控制播放、暂停
// 歌曲列表
public List<Messageinfo>list;
// 获取Main界面的布局 以及context
private LayoutInflater mInflater;
private Context context;
// 更新歌曲
final private int NOW = 9;
public TextAdapter(List<Messageinfo>list, Context context)
{
super();
// 接收数据
this.list = list;
// 获取Main界面的布局 以及context
mInflater = LayoutInflater.from(context);
this.context = context;
}
@Override
public int getCount() {
return list.size();
}
@Override
public Object getItem(int i) {
return list.get(i);
}
@Override
public long getItemId(int i) {
return i;
}
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
// 复用,降低时间复杂度
ViewHolder holder = null;
if(view == null) {
view = mInflater.inflate(R.layout.item, viewGroup,false);
// 可以被重用的视图 两个参数 第一个参数就是 分布的资源id 第二个就是填充的根视图
holder = new ViewHolder();
// 两个文本框 标题以及作者
holder.txt1 = (TextView) view.findViewById(R.id.txt1);
holder.txt2 = (TextView) view.findViewById(R.id.txt2);
// 布局
holder.ll1 = (LinearLayout) view.findViewById(R.id.ll1);
view.setTag(holder);
}
else
holder = (ViewHolder) view.getTag();
Messageinfo mess = list.get(i);
/// 填充数据
holder.txt1.setText("歌曲:" + mess.getTitle());
holder.txt2.setText( "歌手:" + mess.getAuthor());
// 添加监听
holder.ll1.setOnClickListener( new ClickListener(i));
return view;
}
class ClickListener implements Button.OnClickListener{
// 标记位确定是哪一个列表项
private int position;
public ClickListener(int i)
{
this.position = i;
}
@Override
public void onClick(View v){
// 创建 Intent
Intent intent = new Intent(CONTROL);
// 设置广播频道:用户修改播放歌曲
intent.putExtra("control", NOW);
// 传回播放歌曲序号
intent.putExtra("now",position);
// 按意图发送广播
context.sendBroadcast(intent);
}
};
/// 复用类
public final class ViewHolder{
public TextView txt1;
public TextView txt2;
LinearLayout ll1;
}
}
MusicService.java
package com.example.musicdemo;
import android.app.Activity;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.database.Cursor;
import android.media.MediaPlayer;
import android.os.Environment;
import android.os.IBinder;
import android.provider.MediaStore;
import android.util.Log;
import android.view.LayoutInflater;
import android.widget.Adapter;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.SeekBar;
import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class MusicService extends Service {
// 当前的状态,0x11 代表没有播放 0x12代表 正在播放 0x13 代表暂停
final private int NOPLAY = 0x11;
final private int PLAYING = 0x12;
final private int PAUSE = 0x13;
// 状态标记位
private int status = NOPLAY;
//定义UI界面上的各按钮按下时所代表的控制信号
final private int PLAY_OR_PAUSE = 1;
final private int STOP = 2;
final private int NEXT = 3;
final private int PREVIOUS = 4;
final private int LOOP = 5;
final private int RANDOM = 6;
final private int LOOP_ALL = 7;
final private int PROGRESS = 8;
final private int NOW = 9;
// 当前歌曲总时长
private int currentDuration = 0;
// 循环形式标记位 0代表列表循环 1代表单曲循环 2代表随机播放
private int loop_type = 0;
// 歌曲总数
private int songsCount = 0;
// 记录当前正在播放的音乐
private int current = 0;
// 进度条下面的当前进度文字,将毫秒化为m:ss格式
private SimpleDateFormat time = new SimpleDateFormat("mm:ss");
// 广播接收器
private ServiceReceiver serviceReceiver;
// 音乐播放器组件
private MediaPlayer mPlayer;
// 线程运行状态标记位 true表示正在运行
private boolean isRunning;
// 播放的音乐列表
List<Messageinfo>info;
// 线程
Thread thread;
public MusicService() {
}
@Override
public IBinder onBind(Intent intent) {
throw new UnsupportedOperationException("Not yet implemented");
}
public void onCreate(){
// 创建BroadcastReceiver
serviceReceiver = new ServiceReceiver();
// 初始化数据
info = new ArrayList<Messageinfo>();
initSongsData();
songsCount = info.size();
// 创建IntentFilter,MainActivity.CONTROL代表接收信息来源
IntentFilter filter = new IntentFilter(MainActivity.CONTROL);
// 注册广播接收器
registerReceiver(serviceReceiver, filter);
// 创建MediaPlayer
mPlayer = new MediaPlayer();
// 播放当前第一首歌曲
Intent sendIntent = new Intent(MainActivity.UPDATE);
// 获取第一首歌曲信息
Messageinfo messageinfo = info.get(current);
// 按照路径准备歌曲
prepareAndPlay((File)messageinfo.getPath());
// 更新状态
status = PLAYING;
// 广播更新信息
sendIntent.putExtra("update", status);
sendIntent.putExtra("songs_title",(String)messageinfo .getTitle());
sendIntent.putExtra("songs_author",(String)messageinfo.getAuthor());
// 发送广播 ,将被MainActivity组件中的BroadcastReceiver接收到
sendIntent.putExtra("songs_duration", mPlayer.getDuration());
sendBroadcast(sendIntent);
// 为MediaPlayer播放完成事件绑定监听器
mPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener(){
public void onCompletion(MediaPlayer mp){
// 完成播放查看当前的循环标记位
/*
列表循环直接下一首
单曲循环则歌曲标记current不需要做更新操作,下一次直接继续播放之前的音乐
随机播放直接在[0,info.size()-1]范围内随机数
*/
if (loop_type==0) setNextMusic();
else if (loop_type==1);
else if (loop_type==2)
{
int max=info.size()-1,min=0;
long randomNum = System.currentTimeMillis();
current = (int) (randomNum%(max-min)+min);
}
/* 发送广播通知Activity更改文本框 */
Intent sendIntent = new Intent(MainActivity.UPDATE);
Messageinfo messageinfo = info.get(current);
prepareAndPlay((File)messageinfo.getPath());
status = PLAYING;
sendIntent.putExtra("update", status);
sendIntent.putExtra("songs_title",(String)messageinfo .getTitle());
sendIntent.putExtra("songs_author",(String)messageinfo.getAuthor());
// 发送广播 ,将被Activity组件中的BroadcastReceiver接收到
sendIntent.putExtra("songs_duration", mPlayer.getDuration());
sendBroadcast(sendIntent);
// 准备、并播放音乐
}
});
super.onCreate();
// 设置线程循环控制变量为真
isRunning = true;
// 创建线程更新播放进度
// 判断音乐是否在播放
// 创建意图 :更新播放进度
// 让意图携带当前播放时点
// 按意图发送广播
// 让线程睡眠500毫秒
thread = new Thread(new Runnable() {
@Override
public void run() {
while (isRunning) {
// 判断音乐是否在播放
if (mPlayer.isPlaying()) {
// 创建意图 :更新播放进度
Intent sendIntent = new Intent(MainActivity.UPDATE);
sendIntent.putExtra("update", status);
// 让意图携带当前播放时点
sendIntent.putExtra("current_position", mPlayer.getCurrentPosition());
sendIntent.putExtra("songs_duration",mPlayer.getDuration());
// 按意图发送广播
sendBroadcast(sendIntent);
}
// 让线程睡眠500毫秒
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
// 启动线程
thread.start();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// 后台重启时更新页面,恢复到退出之前的状态
Intent sendIntent = new Intent(MainActivity.UPDATE);
Messageinfo messageinfo = info.get(current);
status = PLAYING;
sendIntent.putExtra("update", status);
sendIntent.putExtra("songs_title", (String) messageinfo.getTitle());
sendIntent.putExtra("songs_author", (String) messageinfo.getAuthor());
sendIntent.putExtra("songs_duration",mPlayer.getDuration());
// 按意图发送广播
sendBroadcast(sendIntent);
return super.onStartCommand(intent, flags, startId);
}
// 下一首更新标记即可,溢出清零
private void setNextMusic()
{
current++;
if (current >= songsCount){
current = 0;
}
}
// 上一首更新标记即可,越界设置最后一首
private void setPrieviousMusic()
{
current--;
if (current <0){
current = songsCount-1;
}
}
// 初始化MediaPlayer歌曲路径,让MediaPlayer进入到准备状态
private void initSongsData() {
// 查询数据库
Cursor cursor = getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,null,null,null,null);
while (cursor.moveToNext())
{
// 获取所有歌曲的名称、作者、以及播放路径
String title = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DISPLAY_NAME));
String author = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ARTIST));
String Data = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA));
Messageinfo messageinfo = new Messageinfo(title,author,new File(Data));
// 添加到封装类
info.add(messageinfo);
}
}
public class ServiceReceiver extends BroadcastReceiver {
public void onReceive(final Context context, Intent intent){
// 更新音乐 control代表更新播放音乐,update代表更新图片以及音乐信息
int control = intent.getIntExtra("control", -1);
// 获取当前音乐
Messageinfo messageinfo = info.get(current);
// 标记当前是更新循环格式还是更新状态 false代表循环格式
boolean flag = true;
switch (control){
// 播放或暂停
case PLAY_OR_PAUSE:
// 原来处于没有播放状态
if (status == NOPLAY){
// 准备、并播放音乐
prepareAndPlay((File)messageinfo.getPath());
// 更新状态
status = PLAYING;
}
// 原来处于播放状态
else if (status == PLAYING){
// 暂停
mPlayer.pause();
// 改变为暂停状态
status = PAUSE;
}
// 原来处于暂停状态
else if (status == PAUSE){
// 播放
mPlayer.start();
// 改变状态
status = PLAYING;
}
break;
// 停止声音
case STOP:
// 如果原来正在播放或暂停
if (status == PLAYING || status == PAUSE){
// 标记位清零
current = 0;
// 重置歌曲
mPlayer.reset();
// 状态更改为未播放
status = NOPLAY;
}
break;
// 下一首
case NEXT:
// 更新 current
setNextMusic();
// 更新状态
status = PLAYING;
// 获取下一首歌曲的信息
messageinfo = info.get(current);
// 准备播放下一首
prepareAndPlay((File)messageinfo.getPath());
break;
// 上一首
case PREVIOUS:
// 更新 current
setPrieviousMusic();
// 更新状态
status = PLAYING;
// 获取上一首歌曲的信息
messageinfo = info.get(current);
// 准备播放上一首
prepareAndPlay((File)messageinfo.getPath());
break;
// 进度条被拖拽
case PROGRESS:
// 状态转化为播放
status = PLAYING;
// 获取进度百分比 (整数)
int progress = intent.getIntExtra("progress", -1);
mPlayer.seekTo(progress*currentDuration/100);
break;
// 列表项被点击切换歌曲
case NOW:
// 状态转化为播放
status = PLAYING;
// 获取被点击歌曲的序号
int x= intent.getIntExtra("now", 0);
// 更新歌曲
prepareAndPlay((File)info.get(x).getPath());
messageinfo = info.get(x);
// 更新current
current = x;
break;
// 列表循环
case LOOP_ALL:
flag = false;
loop_type = 0;
break;
// 单曲循环
case LOOP:
flag = false;
loop_type = 1;
break;
// 随机播放
case RANDOM:
flag = false;
loop_type = 2;
break;
}
// 当前是更新信息并非更新循环样式,循环样式要等到歌曲结束才更新信息
if (flag) {
/* 发送广播通知Activity更改图标、文本框 */
Intent sendIntent = new Intent(MainActivity.UPDATE);
sendIntent.putExtra("update", status);
sendIntent.putExtra("songs_title", (String) messageinfo.getTitle());
sendIntent.putExtra("songs_author", (String) messageinfo.getAuthor());
if (status == NOPLAY) {
sendIntent.putExtra("songs_title", "");
sendIntent.putExtra("songs_author", "");
}
if (status == PLAYING || status == PAUSE)
sendIntent.putExtra("songs_duration", mPlayer.getDuration());
// 发送广播 ,将被Activity组件中的BroadcastReceiver接收到
sendBroadcast(sendIntent);
}
}
}
private void prepareAndPlay(File songsPath){
try{
mPlayer.reset();
// 使用MediaPlayer加载指定的声音文件。
mPlayer.setDataSource(songsPath.getPath());
// 准备声音
mPlayer.prepare();
// 获取总时长
currentDuration = mPlayer.getDuration();
// 播放
mPlayer.start();
}
catch (IOException e){
e.printStackTrace();
}
}
@Override
public void onDestroy() {
super.onDestroy();
// 解除注册
unregisterReceiver(serviceReceiver);
// 释放媒体播放器
if (mPlayer != null) {
mPlayer.stop();
mPlayer.release();
mPlayer = null;
}
// 设置线程循环控制变量
isRunning = false;
// 销毁子线程
thread = null;
}
}
Messageinfo.java
package com.example.musicdemo;
import java.io.File;
public class Messageinfo {
// 歌曲标题
private String title;
// 歌曲作者
private String author;
// 歌曲路径
private File path;
//构造方法
public Messageinfo(String title,String author,File path) {
this.title = title;
this.author = author;
this.path = path;
}
public String getTitle()
{
return title;
}
public String getAuthor()
{
return author;
}
public File getPath()
{
return path;
}
}