Android通過(guò)startService播放背景音樂(lè)
關(guān)于startService的基本使用概述及其生命周期可參見《Android中startService基本使用方法概述》。
本文通過(guò)播放背景音樂(lè)的簡(jiǎn)單示例,演示startService的基本使用流程,具體內(nèi)容如下
系統(tǒng)界面如下:
界面上面就兩個(gè)按鈕,”播放音樂(lè)并退出Activity” 和 “停止播放音樂(lè)”。我們?cè)谠撌纠校ㄟ^(guò)操縱Activity的按鈕控制MusicService播放或停止播放音樂(lè)。
我將一個(gè)名為music.mp3的放到資源目錄/res/raw文件夾下面,這樣我們?cè)诔绦蛑芯涂梢酝ㄟ^(guò)R.raw.music引用該音樂(lè)文件,放入/res/raw文件夾中的資源文件會(huì)保持原來(lái)的面貌不會(huì)被編譯成二進(jìn)制。
MusicService是用于播放背景音樂(lè)的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的生命周期中只會(huì)調(diào)用一次 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){ //將背景音樂(lè)設(shè)置為循環(huán)播放 mediaPlayer.setLooping(true); } } @Override public int onStartCommand(Intent intent, int flags, int startId) { //每次調(diào)用Context的startService都會(huì)觸發(fā)onStartCommand回調(diào)方法 //所以onStartCommand在Service的生命周期中可能會(huì)被調(diào)用多次 if(isReady && !mediaPlayer.isPlaying()){ //播放背景音樂(lè) mediaPlayer.start(); Toast.makeText(this, "開始播放背景音樂(lè)", Toast.LENGTH_LONG).show(); } return START_STICKY; } @Override public IBinder onBind(Intent intent) { //該Service中不支持bindService方法,所以此處直接返回null return null; } @Override public void onDestroy() { //當(dāng)調(diào)用Context的stopService或Service內(nèi)部執(zhí)行stopSelf方法時(shí)就會(huì)觸發(fā)onDestroy回調(diào)方法 super.onDestroy(); if(mediaPlayer != null){ if(mediaPlayer.isPlaying()){ //停止播放音樂(lè) mediaPlayer.stop(); } //釋放媒體播放器資源 mediaPlayer.release(); Toast.makeText(this, "停止播放背景音樂(lè)", 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){ //播放背景音樂(lè) Intent intent = new Intent(this, MusicService.class); startService(intent); //退出當(dāng)前Activity this.finish(); }else if(v.getId() == R.id.btnStop){ //停止播放音樂(lè) Intent intent = new Intent(this, MusicService.class); stopService(intent); } } }
當(dāng)我們單擊了按鈕”播放音樂(lè)并退出Activity”之后,我們首先通過(guò)Activity的startService啟動(dòng)MusicService,然后我們立即調(diào)用了Activity的finish方法銷毀了當(dāng)前的Activity??赡艽蠹視?huì)問(wèn)為什么要銷毀當(dāng)前的Activity?我們此處之所以調(diào)用Activity的finish方法不是從功能的角度出發(fā)的,而是從理解代碼運(yùn)行的角度故意這么寫的: 執(zhí)行完Activity的finish方法之后,當(dāng)前的Activity就銷毀了, 在界面上看起來(lái)就是當(dāng)前UI消失了,應(yīng)用程序退出了,但稍等片刻你會(huì)聽到背景音樂(lè)響起。這從側(cè)面印證了Service的一個(gè)特性: Service與Activity等一樣,也是一種基本的應(yīng)用程序組件,Service無(wú)需依賴任何的Activity便可獨(dú)自在沒(méi)有任何UI界面的情況下悠閑地在Android后臺(tái)默默運(yùn)行。
調(diào)用了startService之后,Android Framework接收到了intent信息,第一次會(huì)先創(chuàng)建MusicService的實(shí)例,執(zhí)行MusicService的onCreate回調(diào)方法,onCreate在Service的生命周期中只會(huì)調(diào)用一次,我們?cè)谄鋙nCreate方法中將R.raw.music初始化為媒體播放器,并調(diào)用媒體播放器的prepare方法。然后我們將播放器設(shè)置為循環(huán)播放狀態(tài)。需要注意的是,在實(shí)際生產(chǎn)環(huán)境中,我們應(yīng)該注冊(cè)播放器的setOnPreparedListener并調(diào)用prepareAsync()方法,為了簡(jiǎn)化代碼起見,我們只調(diào)用了播放器的同步方法prepare()。
調(diào)用了onCreate方法后,Android會(huì)自動(dòng)回調(diào)其onStartCommand方法,其實(shí)每次調(diào)用Context的startService都會(huì)觸發(fā)onStartCommand回調(diào)方法,所以onStartCommand在Service的生命周期中可能會(huì)被調(diào)用多次。所以我們?cè)贛usicService的onStartCommand中做了判斷,判斷播放器是否是在播放中,如果當(dāng)前播放器沒(méi)有播放我們才調(diào)用播放器的start方法播放背景音樂(lè)。
當(dāng)我們單擊了按鈕”播放音樂(lè)并退出Activity”之后,MusicService啟動(dòng)起來(lái),播放背景音樂(lè),但是Activity卻銷毀了,程序的UI界面不見了。為了能夠停止播放背景音樂(lè),我們需要再次單擊應(yīng)用程序圖標(biāo),重新打開MusicActivity,然后單擊界面上的”停止播放音樂(lè)”按鈕,此時(shí)我們會(huì)調(diào)用Activity的stopService方法,Android Framework接收到要停止服務(wù)的intent之后會(huì)回調(diào)MusicService的onDestroy方法,在該方法中我們停止播放音樂(lè)并釋放媒體播放器資源。
本文只是通過(guò)播放背景音樂(lè)這一簡(jiǎn)單示例演示通過(guò)startService啟動(dòng)Service基本使用流程,代碼沒(méi)有進(jìn)行優(yōu)化,希望對(duì)大家學(xué)習(xí)Service有所幫助。
相關(guān)文章
listView的item中有checkbox,導(dǎo)致setOnItemClick失效的原因及解決辦法
這篇文章主要介紹了listView的item中有checkbox,導(dǎo)致setOnItemClick失效的原因及解決辦法,需要的朋友可以參考下2017-01-01Android編程添加快捷方式(Short)到手機(jī)桌面的方法(含添加,刪除及查詢)
這篇文章主要介紹了Android編程添加快捷方式(Short)到手機(jī)桌面的方法,含有針對(duì)桌面快捷方式的添加,刪除及查詢的操作實(shí)現(xiàn)技巧,需要的朋友可以參考下2016-01-01Android自定義View實(shí)現(xiàn)開關(guān)按鈕
android 自定義view知識(shí)非常廣泛,難以讓人掌握。但是也是andoroid進(jìn)階學(xué)習(xí)的必經(jīng)之路。下面通過(guò)本文給大家介紹Android自定義View實(shí)現(xiàn)開關(guān)按鈕的知識(shí),非常不錯(cuò),感興趣的朋友一起看看吧2016-11-11Android啟動(dòng)模擬器報(bào)錯(cuò)解決方法
本文將詳細(xì)介紹Android模擬器報(bào)"Failed To Allocate memory 8"錯(cuò)誤的解決辦法,需要了解的朋友可以參考下2012-12-12Android中使用Vectors(2)繪制優(yōu)美的路徑動(dòng)畫
這篇文章主要介紹了Android中使用Vectors(2)繪制優(yōu)美的路徑動(dòng)畫的相關(guān)資料,需要的朋友可以參考下2016-03-03詳解Android 8.1.0 Service 中 彈出 Dialog的方法
這篇文章主要介紹了Android 8.1.0 Service 中怎么彈出 Dialog問(wèn)題,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-10-10詳解Android JetPack之LiveData的工作原理
這篇文章主要介紹了詳解Android JetPack之LiveData的工作原理,幫助大家更好的理解和學(xué)習(xí)使用Android開發(fā),感興趣的朋友可以了解下2021-03-03Android RecyclerView區(qū)分視圖類型的Divider的實(shí)現(xiàn)
本篇文章主要介紹了Android RecyclerView區(qū)分視圖類型的Divider的實(shí)現(xiàn),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-04-04