第4節 播放服務的搭建
播放音樂的服務-
MusicService
是整改音樂播放器的核心,它将播放界面和實際的播放功能連接配接在一起。
4.1 MusicService的接口
它對外要提供兩類主要的功能,播放音樂的控制接口和播放清單的存取接口。
4.1.1 播放音樂的控制接口
根據功能的定義,我們認為控制接口應該包括:
play():播放播放清單中應該要播放的音樂;
playPre():播放播放清單中的上一首音樂;
playNext():播放播放清單中的下一首音樂;
pause():暫停播放;
isPlaying():目前音樂是否處于播放的狀态;
seekTo():将目前音樂播放的進度,拖動到指定的位置;
getCurrentMusicItem():擷取目前正在播放的音樂的資訊;
MusicListActivity
為了擷取
MusicService
的狀态,還需要設定監聽器,當
MusicService
有變化時,能主動通知到
MusicListActivity
。是以要有監聽函數:
registerOnStateChangeListener():注冊監聽函數
unregisterOnStateChangeListener():登出監聽函數
監聽時要擷取的資訊包括:
- 播放進度的改變;
- 音樂開始播放;
- 音樂停止播放;
是以設計監聽器的接口為,
public interface OnStateChangeListenr {
//用來通知播放進度
void onPlayProgressChange(MusicItem item);
//用來通知目前處于播放狀态
void onPlay(MusicItem item);
//用來通知目前處于暫停或停止狀态
void onPause(MusicItem item);
}
當然,還可以設計擷取更多的資訊,這裡我們就簡單的擷取這幾種簡單的資訊。隻要知道了設計的原理,我們就可以在以後随心所欲的改造。
4.1.2. 播放清單的存取接口;
MusicService
通過操作
PlayListContentProvider
來實作對音樂清單的存取。
MusicService
對外提供這樣的接口:
getPlayList():擷取播放清單
addPlayList():添加播放清單。這裡添加清單應該有兩種形式,一種是一次性添加多首音樂,一種是一次就添加一首音樂。
4.2 Service的使用
安卓系統的
Service
按照建立的方式進行分類,有兩種:啟動Service-
start Service
,綁定Service-
bind Service
。前者使用
startService()
運作,後者使用
bindService()
運作。
4.2.1 Start Service
其他元件通過調用
startService()
函數将
Service
運作起來,再通過調用
stopService()
函數讓其停止運作。
單純的使用這種形式的
Service
最為簡單,它和它的調用者之間沒有什麼聯系,調用者隻是負責啟動它和停止它,或者在啟動它的時候通過Intent傳遞一點資料,除此之外,兩者沒有資料交換、沒有其他的功能調用,這兩個元件之間基本上互不影響。
設計這樣的一個
Service
需要,
- 繼承Android SDK提供的
類,重寫Service
函數,讓它傳回空值;onBind()
public class MyService extends Service { public MyService() { } @Override public IBinder onBind(Intent intent) { //不需要調用者和Service有功能調用,傳回空值 return null; } ...... }
- 在
中,聲明新建立的AndroidManifest.xml
,Service
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android"> ...... <application ...... android:theme="@style/AppTheme"> ...... <!--聲明新建立的Service--> <service android:name=".MyService" android:enabled="true" android:exported="true"></service> </application> </manifest>
使用這種
Service
也很簡單。假設Activity A中有個按鈕start,點選之後就調用
startService
;還有個按鈕B-stop,點選之後就調用
stopService
。
public void onClick(View v)
{
switch (v.getId())
{
case R.id.start:
{
//啟動Service
Intent i = new Intent(this, MyService.class);
startService(i);
}
break;
case R.id.stop:
{
//停止Service
Intent i = new Intent(this, MyService.class);
stopService(i);
}
break;
}
}
這裡運作Service的時候,是通過
Intent
明确指定被運作的
Service
。這種明确指定啟動哪個
Service
的方式叫做
Service
的顯示調用。與之對應的還有隐式調用,通過
action
來啟動。
4.2.2 Bind Service
其他元件通過調用
bindService()
綁定
Service
,讓它運作起來;再通過調用
unbindService()
解除綁定。
這種形式的
Service
與調用者之間通常有功能調用或者頻繁的資料交換,
Service
會提供接口給其它子產品調用,
設計這樣的一個
Service
需要,
- 繼承Android SDK提供的
類,Service
public class MyService extends Service { public MyService() { } @Override public IBinder onBind(Intent intent) { //暫時傳回空值,寫下來将進行改造 return null; } ...... }
- 實作一個自定義的
,讓它這個繼承Binder
類。Binder
可以将Binder
與調用者聯系起來,在Service
中提供的方法,就是Binder
Service
對外提供的方法。
元件和
之間的調用是通過Service
來進行的。我們可以把Binder
看作是一個連接配接其他元件和Binder
的橋梁,它的實作原理是什麼,我們暫時不用去關心,隻要知道這樣用就可以了。Service
public class MyService extends Service { ...... //建立一個自定義的Binder public class MyServiceIBinder extends Binder { //提供給其他元件調用的方法 public void function1(int param){ //調用Service中真正實作功能的方法 innerFunction1(param); } } //真正實作功能的方法 private void innerFunction1(int param) { } //建立Binder執行個體 private final IBinder mBinder = new MyServiceIBinder(); @Override public IBinder onBind(Intent intent) { //當元件bindService()之後,将這個Binder傳回給元件使用 return mBinder; } ...... }
- 在
中,聲明新建立的AndroidManifest.xml
,Service
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android"> ...... <application ...... android:theme="@style/AppTheme"> ...... <!--聲明新建立的Service--> <service android:name=".MyService" android:enabled="true" android:exported="true"></service> </application> </manifest>
其他元件使用這個
Service
的時候,
- 建立一個
,當綁定ServiceConnection
之後,在Service
中會得到onServiceConnected()
傳回的Service
;如果Service遇到異常情況退出時,會通過Binder
通知綁定它的元件。onServiceDisconnected()
獲得了private ServiceConnection mServiceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { //這裡的service參數,就是Service當中onBind()傳回的Binder //擷取通路Service的橋梁-MyServiceIBinder MyService.MyServiceIBinder bridge = (MyService.MyServiceIBinder) service; //通過橋梁就可以調用到Service提供到函數了 bridge.function1(); } @Override public void onServiceDisconnected(ComponentName name) { //當Service遇到異常情況退出時,會通過這裡通知綁定過它的元件 } };
之後,我們就可以向調用普通函數那樣,調用到MyService.MyServiceIBinder
Service
對外提供的接口函數了。
需要注意的是,如果使用者主動解除綁定,
是不會被觸發的。onServiceDisconnected()
- 假設Activity A中有個按鈕,點選之後就調用
;還有個按鈕B,點選之後就調用bindService
。unbindService
這裡同樣采用的是對public void onClick(View v) { switch (v.getId()) { case R.id.start: { Intent i = new Intent(this, MyService.class); bindService(i, mServiceConnection, Context.BIND_AUTO_CREATE); } break; case R.id.stop: { unbindService(mServiceConnection); } break; } }
的顯示調用。Service
4.2.3 混合模式
Service
并不是隻能給一個元件使用,它可以同時服務于多個元件。
是以一個
Service
既可以是
Start Service
,也可以是
Bind Service
。隻要把兩者需要實作的地方都實作了就行。元件A可以通過
startService()
運作一個
Service
,元件B可以通過
bindService()
再次運作同一個
Service
。
4.3 MusicService的建立
根據上面的介紹可以知道,因為
MusicService
要為其它元件提供調用的接口,是以它至少是一個
Bind Service
。
MusicListActivity
通過
MusicService
提供的
IBinder
對象,使用
bindService()
方式與之建立聯系,擷取播放音樂、暫停音樂等等一系列與播放音樂有關的操作方法;
是以
MusicService
應該按照如下方式設計,
public class MusicService extends Service {
......
public class MusicServiceIBinder extends Binder {
public void addPlayList(List<MusicItem> items) {
addPlayListInner(items);
}
public void addPlayList(MusicItem item) {
addPlayListInner(item);
}
public void play() {
playInner();
}
public void playNext() {
playNextInner();
}
public void playPre() {
playPreInner();
}
public void pause() {
pauseInner();
}
public void seekTo(int pos) {
seekToInner(pos);
}
public void registerOnStateChangeListener(OnStateChangeListenr l) {
registerOnStateChangeListenerInner(l);
}
public void unregisterOnStateChangeListener(OnStateChangeListenr l) {
unregisterOnStateChangeListenerInner(l);
}
public MusicItem getCurrentMusic() {
return getCurrentMusicInner();
}
public boolean isPlaying() {
return isPlayingInner();
}
public List<MusicItem> getPlayList() {
return null;
}
}
//真正實作功能的方法
public void addPlayListInner(List<MusicItem> items) {
}
public void addPlayListInner(MusicItem item) {
}
public void playNextInner() {
}
public void playInner() {
}
public void playPreInner() {
}
public void pauseInner() {
}
public void seekToInner(int pos) {
}
public void registerOnStateChangeListenerInner(OnStateChangeListenr l) {
}
public void unregisterOnStateChangeListenerInner(OnStateChangeListenr l) {
}
public MusicItem getCurrentMusicInner() {
return null;
}
public boolean isPlayingInner() {
return false;
}
//建立Binder執行個體
private final IBinder mBinder = new MusicServiceIBinder();
@Override
public IBinder onBind(Intent intent) {
//當元件bindService()之後,将這個Binder傳回給元件使用
return mBinder;
}
......
}
4.4 MusicService的使用
MusicListActivity
綁定
MusicService
的時候,就先定義一個
ServiceConnection
:
private MusicService.MusicServiceIBinder mMusicService;
private ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//綁定成功後,取得MusicSercice提供的接口
mMusicService = (MusicService.MusicServiceIBinder) service;
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
然後在
onCreate()
當中,實作綁定的操作,
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_music_list);
Intent i = new Intent(this, MusicService.class);
//啟動MusicService
startService(i);
//實作綁定操作
bindService(i, mServiceConnection, BIND_AUTO_CREATE);
}
當
MusicListActivity
退出的時候,需要将
MusicService
解除綁定,
@Override
protected void onDestroy() {
super.onDestroy();
......
unbindService(mServiceConnection);
......
}
這裡需要注意一個細節:在綁定
MusicService
之前,我們先做了一次
startService()
。假如不先
startService()
,那麼當
MusicListActivity
退出(onDestroy())的時候,
MusicService
将會被銷毀掉(因為調用了unbindService())。
如果用先用
startService()
啟動了這個服務,那麼要停止它,就必須使用
stopService()
了。不過在整個音樂的設計當中,我們并沒有想過要讓
MusicService
停止工作,而是隻要它運作起來了,就一直在背景待命。
至此,
MusicService
的架子已經搭建完畢。
/*******************************************************************/
* 版權聲明
* 本教程隻在CSDN和安豆網釋出,其他網站出現本教程均屬侵權。
*另外,我們還推出了Arduino智能硬體相關的教程,您可以在我們的網店跟我學Arduino程式設計中購買相關硬體。同時也感謝大家對我們這些碼農的支援。
*最後再次感謝各位讀者對
安豆
的支援,謝謝:)
/*******************************************************************/