簡易音樂播放器(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;
}
}
