這只是一個小例子,實現三首mp3格式音樂的循環播放,並且有播放、暫停、停止的功能。
大體思想:
-
需要一個Activity用來與用戶交互當前播放情況,用戶通過點擊按鈕操作播放、暫停和停止。
-
還需要有一個后台Service處理音樂的播放(還好Android有MediaPlayer對象可以對音樂進行播放、暫停等操作)。
-
Activity和Service之間需要進行交互,
(1)用戶點擊按鈕執行音樂的播放、暫停或者停止,每一個按鈕對應一種狀態,通過Broadcast廣播傳給Service。
(2)Service接收Activity發來的廣播,對操作進行判斷從而執行MediaPlayer的音樂操作。之后將音樂的信息同樣以廣播的形式發送回Activity。
(3)Activity接收Service的廣播在頁面上更新歌曲的信息。
下面是細節的問題:
1.首先Activity布局非常簡單,一個文本框用來顯示歌曲名,兩個按鈕,“播放”和“停止”。
2.然后是Activity:
(1)onCreate()方法:
這是Activity第一次創建的時候調用的,因此默認代碼就是將布局文件進行加載。除了這些內容,我們要獲取獲取布局文件上的組件,尤其是Button,我們需要定義監聽器處理用戶點擊的事件(一會就會說到)。其實最主要的兩件事是創建BroadcastReceiver對象、Intent過濾器和Receiver的注冊(Broadcast不同於監聽器,Broadcast是一個系統級的監聽器,擁有自己的進程,因此只要存在與之匹配的Intent被廣播出來,BroadcastReceiver總會被觸發),然后開啟后台的Service。
ar = new ActivityReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction(UPDATE_ACTION); //update更改界面播放信息
getApplicationContext().registerReceiver(ar,filter);
Intent in = new Intent(MainActivity.this,MP3Service.class);
startService(in); //開啟Service
(2)定義BroadcastReceiver的子類並重寫onReceive方法,這是Service發送歌曲信息的廣播,然后Activity獲取並更新頁面的Receiver:onReceive方法在應用發送相應廣播后自動執行,執行之后BroadcastReceiver實例就會被銷毀。
public class ActivityReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
System.out.println("activity receive");
int update = intent.getIntExtra("update", -1);
int current = intent.getIntExtra("current", -1);
if(current>=0){
title.setText(titleStrs[current]);
}
switch(update){
case 0x11:
play.setText(R.string.play);
break;
case 0x12:
play.setText(R.string.pause);
break;
case 0x13:
play.setText(R.string.play);
break;
}
}
}
(3)onClick:首先Activity有兩個按鈕,定義一個control狀態代表哪個按鈕被執行,播放和暫停是一類的,停止是第二類的,將哪個按鈕被執行的control狀態封裝到Intent中,然后發送廣播給Service。
public void onClick(View source) {
Intent in = new Intent(CTL_ACTION); //Service中廣播處理的是CTL_ACTION的Intent
switch(source.getId()){
case R.id.play:
in.putExtra("control", 1);
break;
case R.id.stop:
in.putExtra("control", 2);
break;
}
sendBroadcast(in);//發送廣播到service
System.out.println("activity send");
}
(4)onDestroy:最后,因為Service是Activity開啟的,而且同樣在onCreate中注冊了BroadcastReceiver,因此當Activity被銷毀時,也需要將Service和BroadcastReceiver釋放:
protected void onDestroy() {
stopService(in);
getApplicationContext().unregisterReceiver(ar);
super.onDestroy();
}
3.接着是Service:
(1)onCreate:創建MediaPlayer對象,為MediaPlayer設置CompletingListener監聽器(當前數據被播放完之后執行,用來播放下一首),創建AssetManager對象用於讀取sdcard的音樂文件,並創建接收Activity廣播的BroadcastReceiver:
asset = getAssets();
mr = new MyReceiver();
IntentFilter filter = new IntentFilter(MainActivity.CTL_ACTION); //控制播放
getApplicationContext().registerReceiver(mr,filter);
mp = new MediaPlayer();
(2)MediaPlayer的監聽器:根據current當前歌曲的標號進行歌曲的切換,並發送下一首歌曲的信息通過廣播發送給Activity:
mp.setOnCompletionListener(new OnCompletionListener(){
@Override
public void onCompletion(MediaPlayer mp) {
current = current+1; //從0開始的,0,1,2三首
if(current>=3){
current = 0;
}
//通知界面更新歌曲信息
Intent sendIntent = new Intent(MainActivity.UPDATE_ACTION);
sendIntent.putExtra("current", current);
sendBroadcast(sendIntent);
prepareAndPlay(songs[current]);
}
});
(3)最重要的接收Activity中用戶點擊按鈕的狀態發來的廣播進行音樂播放處理的Receiver:
public class MyReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
System.out.println("serivce receive");
int control = intent.getIntExtra("control",-1);
switch(control){
case 1: //播放或暫停
if(status==0x11){
prepareAndPlay(songs[current]);
status = 0x12;
}
else if(status==0x12){
mp.pause();
status = 0x13;
}
else if(status==0x13){
mp.start();
status = 0x12;
}
break;
case 2: //停止音樂
if(status==0x12||status==0x13){
mp.stop();
status = 0x11;
}
}
Intent sendIntent = new Intent(MainActivity.UPDATE_ACTION);
sendIntent.putExtra("current",current);
sendIntent.putExtra("update", status);
sendBroadcast(sendIntent);
System.out.println("service send");
}
}
(4)最后在onDestroy中釋放Receiver:
public void onDestroy() {
System.out.println("ondestroy");
getApplicationContext().unregisterReceiver(mr);
super.onDestroy();
}
(5)有一個細節,就是在播放完一個歌曲之后,再播放下一個的時候,MediaPlayer對象一定要執行reset方法,不然會發生MediaPlayer狀態的異常。以下是prepareAndPlay方法:
public void prepareAndPlay(String music){
try{
File f = new File(Environment.getExternalStorageDirectory()+"/"+music);
if(f.exists()){
System.out.println("--cunzai--");
}
//AssetFileDescriptor afd = asset.openFd(Environment.getExternalStorageDirectory()+"/"+music);
try {
mp.reset(); //在執行新的一次play的時候需要reset
mp.setDataSource(Environment.getExternalStorageDirectory()+"/"+music);
mp.prepare();
mp.start();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}catch(Exception e){
}
}
4.最后別忘記在Manifest文件中配置Service,由於Receiver是在代碼中生成的,因此無需進行配置。