Android通過startService播放背景音樂簡單示例

孫群發表於2015-08-19

關於startService的基本使用概述及其生命週期可參見部落格《Android中startService的使用及Service生命週期》。

本文通過播放背景音樂的簡單示例,演示startService的基本使用流程。

系統介面如下:
這裡寫圖片描述

介面上面就兩個按鈕,”播放音樂並退出Activity” 和 “停止播放音樂”。我們在該示例中,通過操縱Activity的按鈕控制MusicService播放或停止播放音樂。

我將一個名為music.mp3的放到資源目錄/res/raw資料夾下面,這樣我們在程式中就可以通過R.raw.music引用該音樂檔案,放入/res/raw資料夾中的資原始檔會保持原來的面貌不會被編譯成二進位制。

MusicService是用於播放背景音樂的Service,其程式碼如下所示:

package com.ispring.startservicedemo;

import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.IBinder;
import android.widget.Toast;

import java.io.IOException;

public class MusicService extends Service {

    private MediaPlayer mediaPlayer = null;

    private boolean isReady = false;

    @Override
    public void onCreate() {
        //onCreate在Service的生命週期中只會呼叫一次
        super.onCreate();

        //初始化媒體播放器
        mediaPlayer = MediaPlayer.create(this, R.raw.music);
        if(mediaPlayer == null){
            return;
        }

        mediaPlayer.stop();
        mediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
            @Override
            public boolean onError(MediaPlayer mp, int what, int extra) {
                mp.release();
                stopSelf();
                return false;
            }
        });

        try{
            mediaPlayer.prepare();
            isReady = true;
        } catch (IOException e) {
            e.printStackTrace();
            isReady = false;
        }

        if(isReady){
            //將背景音樂設定為迴圈播放
            mediaPlayer.setLooping(true);
        }
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        //每次呼叫Context的startService都會觸發onStartCommand回撥方法
        //所以onStartCommand在Service的生命週期中可能會被呼叫多次
        if(isReady && !mediaPlayer.isPlaying()){
            //播放背景音樂
            mediaPlayer.start();
            Toast.makeText(this, "開始播放背景音樂", Toast.LENGTH_LONG).show();
        }
        return START_STICKY;
    }

    @Override
    public IBinder onBind(Intent intent) {
        //該Service中不支援bindService方法,所以此處直接返回null
        return null;
    }

    @Override
    public void onDestroy() {
        //當呼叫Context的stopService或Service內部執行stopSelf方法時就會觸發onDestroy回撥方法
        super.onDestroy();
        if(mediaPlayer != null){
            if(mediaPlayer.isPlaying()){
                //停止播放音樂
                mediaPlayer.stop();
            }
            //釋放媒體播放器資源
            mediaPlayer.release();
            Toast.makeText(this, "停止播放背景音樂", Toast.LENGTH_LONG).show();
        }
    }
}

MusicActivity的程式碼如下所示:

package com.ispring.startservicedemo;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;


public class MusicActivity extends Activity implements Button.OnClickListener {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_music);
    }

    @Override
    public void onClick(View v) {
        if(v.getId() == R.id.btnStart){
            //播放背景音樂
            Intent intent = new Intent(this, MusicService.class);
            startService(intent);
            //退出當前Activity
            this.finish();
        }else if(v.getId() == R.id.btnStop){
            //停止播放音樂
            Intent intent = new Intent(this, MusicService.class);
            stopService(intent);
        }
    }
}

當我們單擊了按鈕”播放音樂並退出Activity”之後,我們首先通過Activity的startService啟動MusicService,然後我們立即呼叫了Activity的finish方法銷燬了當前的Activity。可能大家會問為什麼要銷燬當前的Activity?我們此處之所以呼叫Activity的finish方法不是從功能的角度出發的,而是從理解程式碼執行的角度故意這麼寫的: 執行完Activity的finish方法之後,當前的Activity就銷燬了, 在介面上看起來就是當前UI消失了,應用程式退出了,但稍等片刻你會聽到背景音樂響起。這從側面印證了Service的一個特性: Service與Activity等一樣,也是一種基本的應用程式元件,Service無需依賴任何的Activity便可獨自在沒有任何UI介面的情況下悠閒地在Android後臺默默執行。

呼叫了startService之後,Android Framework接收到了intent資訊,第一次會先建立MusicService的例項,執行MusicService的onCreate回撥方法,onCreate在Service的生命週期中只會呼叫一次,我們在其onCreate方法中將R.raw.music初始化為媒體播放器,並呼叫媒體播放器的prepare方法。然後我們將播放器設定為迴圈播放狀態。需要注意的是,在實際生產環境中,我們應該註冊播放器的setOnPreparedListener並呼叫prepareAsync()方法,為了簡化程式碼起見,我們只呼叫了播放器的同步方法prepare()。

呼叫了onCreate方法後,Android會自動回撥其onStartCommand方法,其實每次呼叫Context的startService都會觸發onStartCommand回撥方法,所以onStartCommand在Service的生命週期中可能會被呼叫多次。所以我們在MusicService的onStartCommand中做了判斷,判斷播放器是否是在播放中,如果當前播放器沒有播放我們才呼叫播放器的start方法播放背景音樂。

當我們單擊了按鈕”播放音樂並退出Activity”之後,MusicService啟動起來,播放背景音樂,但是Activity卻銷燬了,程式的UI介面不見了。為了能夠停止播放背景音樂,我們需要再次單擊應用程式圖示,重新開啟MusicActivity,然後單擊介面上的”停止播放音樂”按鈕,此時我們會呼叫Activity的stopService方法,Android Framework接收到要停止服務的intent之後會回撥MusicService的onDestroy方法,在該方法中我們停止播放音樂並釋放媒體播放器資源。

本文只是通過播放背景音樂這一簡單示例演示通過startService啟動Service基本使用流程,程式碼沒有進行優化,希望對大家學習Service有所幫助。

相關文章