2013年1月8日 星期二

[Android]音樂播放 + Service = 可以背景執行的音樂播放程式!

相關 Survey:
程式搖滾-Android Service-幾種應用範例(二)
應用開發筆記-Android Service的使用方法 音乐播放器实例

stuff-[android] 建立service範例


主要參考依據:

Cooking Java - Android學習筆記 - 背景執行服務(Service)

Ray's blog - Android Services使用示例


Android四大元件之一 - Service
從完全沒想法沒概念,到有概念寫出來已經是一天後了,但指令短的可以!
本來以為要將呼叫Service放在Activity中的onDestroy內,這樣可以在按下back鍵時,呼叫Service啟動背景執行的服務,但真的錯了!...錯的可以!

後來好好翻過一些文章仔細閱讀才發現Service是跟Activity並行。
也就是一個音樂播放程式若沒使用Service,即時按home鍵之後音樂還是照播,但是卻沒辦法在設定→應用程式→執行中  看到程式。就這麼消失了,天真的想再執行一次喚回時。
撥放的音樂會跟原本先前撥放的一起撥,吵得可以,最後程式就會出錯。

但是,寫成Service就不相同了
Activity只是顯示元件,撥放的任務則是交給service撥,補充一點Service是沒有UI的,在trace的時候可以用System.out.println("這是從Service發送的訊息");來測試是否有成功呼叫。
若印不出來更別說呼叫到了,沒得trace!

Service就像是一個代理人 將可以背景執行的程序,像MediaPlayer();交給他就對了。

假設這是我選單listview的宣告

ListView lv = (ListView)this.findViewById(R.id.lv);
   File file = new File("/sdcard");
final String filelist[] = file.list();  
ArrayAdapter adapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1,filelist);  
   lv.setAdapter(adapter);


當我在沒有實作Service他的按鍵行為:
lv.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView a, View v, int position, long id) {
mp.reset();
String fid = filelist[position];
selectfile = "/sdcard/" + fid;//將選定的音樂掛上sdcard的路徑assign給selectfile並給setDataSource設定撥放來源.
stop.setEnabled(true);
pause.setEnabled(true);
    try {
    mp.setDataSource(selectfile);//就是這邊 設定撥放音樂來源
    mp.prepare();//通過setDataSource方法設定資料源時 預防 (-38 0) 錯誤,需要在start()之前執行
    } catch (IllegalArgumentException e) {
    } catch (IllegalStateException e) {
    } catch (IOException e) {
    System.out.println("exception : " + e);
    }
    mp.start();//播放。


接下來是改寫成Service的音樂播放程式:
主程式:MainActivity.java

lv.setOnItemClickListener(new OnItemClickListener() {//一樣的按鈕宣告
public void onItemClick(AdapterView a, View v, int position, long id) {
String fid = filelist[position];
selectfile = "/sdcard/" + fid;//一樣的路徑宣告
Intent intent = new Intent(MainActivity.this,MyService.class);//不一樣在這,設定一個intent,intent負責傳值 等同java的事件Event,MainActivity.this是這個程式名稱,,MyService.class是你要傳的Service的程式
intent.putExtra("abc","/sdcard/" + fid);//傳一個選好的檔案路徑,也可以塞selectfile給他,自己都忘了改過來;"abc"你可以想成是intent的id
    startService(intent);//呼叫Service啟動,參照intent資訊傳,並把putExtra塞的訊息傳到目的程式
    }});
然後,MainActivity主程式就做完了!也就是我上述說的將listview上點選的資料透過startService(intent);傳給MyService.java 就做完了!

看完Service的介紹,我們會知道Service在啟動時會先呼叫onCreate();再執行onStart();
應程式實作要求我會寫在onStart這邊。


Service程式   MyService.java      
是 public class MyService extends Service{ }喔!把下面程式塞到這裡面!

public void onStart(Intent intent, int startId) {
        super.onStart(intent, startId);
        String play = intent.getExtras().getString("abc");//將intent傳來的訊息取得"abc"的相對值。這邊很重要,別搞錯哦!不然會像我一樣想了一個下午。若沒概念可以翻翻intent的定義或網路上的資料。
    mp.reset();//確保每次點選音樂她都會重頭播放,暫停功能我有但我寫在pause的button內。
    try {
    System.out.println("Service傳來的信息,收到"+play);//這就是上面一開始所提到的測試訊息。在log中可以看到這行基本上Service是起來的。

//下面就是一樣的播放。
    mp.setDataSource(play);
    //設定播放路徑
    mp.prepare();
    //通過setDataSource方法設定資料源時 預防 (-38 0) 錯誤,需要在start()之前執行
    } catch (IllegalArgumentException e) {
    } catch (IllegalStateException e) {
    } catch (IOException e) {
    System.out.println("exception : " + e);
    }
    mp.start();
    }

此外,我還在AndroidManifest.xml裡面加了料:(轉貼:網友智慧結晶,救了我!)


service android:name=".MyService"/

主要是紅字部分,上下都貼是為了知道貼哪  .MyService是service程式名稱



雖然,可以寫得更好;雖然觀念可能不完全正確,但他終究是work了,聽到音樂那刻我超想哭的!
分享給各位了!希望這篇文章可以讓跟我一樣菜的菜逼八少走一點冤枉路!

沒有留言:

張貼留言