Android歌詞秀設計思路(6)運用Proxy設計模式簡化歌詞播放服務的使用 – Android移動開發技術文章_手機開發 Android移動開發教學課程

開始開發歌詞秀的時候還是夏天,沒有想到寫這篇文章的時候大連已經迎來的今年的第一次大規模降溫。多少有點冬天的感覺瞭。
上一篇文章我們已經介紹瞭,帶有歌詞播放功能的服務,按說接下來就該是利用歌詞播放服務的應用程序瞭。不過我們在這裡要先介紹另外一個類:LyricPlayerServiceProxy,先看一下這個類在整個軟件中的位置。

為什麼要有這麼一個類呢?
原因是:Android裡的服務用起來還不是很方便.
先看下面一段來自Android文檔的的代碼,這段代碼是說明如何使用Service的。
鏈接:http://developer.android.com/reference/android/app/Service.html
 
private LocalService mBoundService;
private ServiceConnection mConnection = new ServiceConnection() {
    public void onServiceConnected(ComponentName className, IBinder service) {
        // This is called when the connection with the service has been
        // established, giving us the service object we can use to
        // interact with the service.  Because we have bound to a explicit
        // service that we know is running in our own process, we can
        // cast its IBinder to a concrete class and directly access it.
        mBoundService = ((LocalService.LocalBinder)service).getService();

        // Tell the user about this for our demo.
        Toast.makeText(Binding.this, R.string.local_service_connected,
                Toast.LENGTH_SHORT).show();
    }
    public void onServiceDisconnected(ComponentName className) {
        // This is called when the connection with the service has been
        // unexpectedly disconnected — that is, its process crashed.
        // Because it is running in our same process, we should never
        // see this happen.
        mBoundService = null;
        Toast.makeText(Binding.this, R.string.local_service_disconnected,
                Toast.LENGTH_SHORT).show();
    }
};

void doBindService() {
    // Establish a connection with the service.  We use an explicit
    // class name because we want a specific service implementation that
    // we know will be running in our own process (and thus won't be
    // supporting component replacement by other applications).
    bindService(new Intent(Binding.this,
            LocalService.class), mConnection, Context.BIND_AUTO_CREATE);
    mIsBound = true;
}

void doUnbindService() {
    if (mIsBound) {
        // Detach our existing connection.
        unbindService(mConnection);
        mIsBound = false;
    }
}

@Override
protected void onDestroy() {
    super.onDestroy();
    doUnbindService();
}
 
代碼本身不算復雜,但是有一點比較討厭,用戶在調用doBindService方法以後,不能立即得到可供使用的服務的實例(mBoundService)。要想使用可供使用的服務的實例,必須要等到ServiceConnection的onServiceConnected方法被調用之後才可以。多少還是有一些不方便的。怎麼解決這個問題呢。
這裡我們使用瞭Proxy(代理)設計模式。在GOF設計模式中代理模式的幾個例子有遠程代理,虛代理,保護代理,智能指引等,這裡的用法和虛代理比較相似,但目的不同。虛代理的目的是有關資源的,這裡是為瞭簡化使用。
找一個生活中真正代理的例子說明一下這種區別吧。
說有一個大牌明星要舉辦一場演唱會,當然事前要做好多準備工作,比如開會啦什麼的,如果每次都是大牌親自去,一個是檔期排不開,另外也太貴瞭,於是好多事就由經紀人代勞,直到真正演出是大牌才出場。這叫虛代理。
和大牌同一個經濟公司有一個剛入行的小演員,公司也給他指派瞭經紀人。由於他還不能獨立演出,公司就安排他給大牌墊場。可是這人有個毛病,早上愛睡懶覺,經常遲到。於是公司就指派他的經紀人先去接受任務,等小演員來瞭在轉告給他。這樣就不會耽誤大牌的演出瞭。
這就是我們今天要說明的場景。為瞭減輕使用者的負擔,我們運用瞭Proxy模式。
先看看數據成員。
private LyricPlayerService mPlaybackService =  null ;
這就是我們的小演員瞭。經濟人雖然不遲到,但是戲還是要演員演。這是我們真正實現功能的服務。
 
接下來就是需要交代給演員做的事瞭。現有經紀人保管著。
private ServiceConnectionListener mConnectionListener = null;
private LyricPlayerService.LyricPlayerListener mLyricListener = null;
private MediaPlayerService.NotificationProvider mNotificationProvider = null;
 
當然瞭,一旦見到小演員,把接到的任務交代給他那也是必須的。
 
private ServiceConnection mPlaybackConnection = new ServiceConnection() {    
          public void onServiceConnected(ComponentName className, IBinder service) {      
              mPlaybackService = ((LyricPlayerService.LocalBinder)service).getService(); 
              mPlaybackService.setLyricPlayerListener(mLyricListener); 
              mPlaybackService.setNotificationProvider(mNotificationProvider); 
              if(mConnectionListener != null){ 
               mConnectionListener.onServiceConnected(); 
              } 
          } 
 
          public void onServiceDisconnected(ComponentName className) { 
           mPlaybackService.setLyricPlayerListener(null); 
           mPlaybackService = null; 
           if(mConnectionListener != null){ 
               mConnectionListener.onServiceDisconnected(); 
              } 
          }    
   };  
 演員新入行,有時需要把一個指令分解,一步一步的指揮。經紀人也不容易啊。
void startAndBindService(){
    mContextWrapper.startService(new Intent(mContextWrapper ,LyricPlayerService.class));   
    mContextWrapper.bindService(new Intent(mContextWrapper, LyricPlayerService.class), mPlaybackConnection, Context.BIND_AUTO_CREATE); 

 
void stopService(){ 
    if(mPlaybackService != null){ 
        mContextWrapper.stopService(new Intent(mContextWrapper ,LyricPlayerService.class)); 
    } 

經紀人做的挺好,幹脆就不見小演員瞭,全又經紀人傳話算瞭,這樣一來,小演員來不來就沒有什麼關系瞭。
public String getTitle(){ 
    if(mPlaybackService != null){ 
        return mPlaybackService.getTitle(); 
    }else{ 
        return null; 
    } 

 
public void setMediaInfoProvider(MediaPlayerService.MediaInfoProvider provider) { 
    mPlaybackService.setMediaInfoProvider(provider); 

 
public void setNotificationProvider(MediaPlayerService.NotificationProvider provider){ 
    mNotificationProvider = provider; 

 
public String getDataSource(){ 
    if(mPlaybackService != null){ 
        return mPlaybackService.getDataSource(); 
    }else{ 
        return null; 
    } 

 
public int getLyricCount(){ 
    if(mPlaybackService != null){ 
        return mPlaybackService.getLyricCount(); 
    }else{ 
        return 0; 
    } 

 
public String getLyric(int index){ 
    if(mPlaybackService != null){ 
        return mPlaybackService.getLyric(index); 
    }else{ 
        return null; 
    } 

 
public void start() { 
    if(mPlaybackService != null){ 
        mPlaybackService.start(); 
    } 
}    
 
public void stop(){ 
    if(mPlaybackService != null){ 
        mPlaybackService.stop(); 
    } 
}    
 
public void pause() { 
    if(mPlaybackService != null){ 
        mPlaybackService.pause(); 
    } 

 
public boolean isPlaying() { 
    if(mPlaybackService != null){ 
        return mPlaybackService.isPlaying(); 
    }else{ 
        return false; 
    } 
}    
 
public boolean isPausing(){ 
    if(mPlaybackService != null){ 
        return mPlaybackService.isPausing(); 
    }else{ 
        return false; 
    } 

 
public int getDuration() { 
    if(mPlaybackService != null){ 
        return mPlaybackService.getDuration(); 
    }else{ 
        return 0; 
    } 
}    
    
public int getPosition() { 
    if(mPlaybackService != null){ 
        return mPlaybackService.getPosition(); 
    }else{ 
        return 0; 
    } 

 
public long seekToLyric(int index){ 
    if(mPlaybackService != null){ 
        return mPlaybackService.seekToLyric(index); 
    }else{ 
        return 0; 
    } 

 
public void seekToNextLyric(){ 
    if(mPlaybackService != null){ 
        mPlaybackService.seekToNextLyric(); 
    } 

 
public void seekToPrevLyric(){ 
    if(mPlaybackService != null){ 
        mPlaybackService.seekToPrevLyric(); 
    } 

 
public long seek(long whereto) { 
    if(mPlaybackService != null){ 
        return mPlaybackService.seek(whereto); 
    }else{ 
        return 0; 
    } 
}    
 
public void setLyricPlayerListener(LyricPlayerService.LyricPlayerListener listener){ 
    mLyricListener = listener; 
    if(mPlaybackService != null){ 
        mPlaybackService.setLyricPlayerListener(mLyricListener); 
    } 
}
 
 軟件的功能介紹,源碼下載:原創:Android應用開發-Andorid歌詞秀,含源碼
作者 “來自大連”

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *