注意:如果你通過(guò)一個(gè)URL來(lái)獲取一個(gè)在線媒體文件,該文件必須能夠支持漸進(jìn)式下載。2.警告:當(dāng)你使用setDataSource()方法時(shí),必須捕捉或通過(guò)非法數(shù)據(jù)異常和輸入輸出異常,因?yàn)檎诒荒阋玫奈募赡懿淮嬖谠?3.
異步準(zhǔn)備 - Asynchronous Preparation
使用MediaPlayer的原則很簡(jiǎn)單。然而,重要的是要記住,有必要將更多的一些東西正確地集成到一個(gè)典型的Android應(yīng)用程序。比如,調(diào)用prepare()方法可能需要較長(zhǎng)的時(shí)間來(lái)執(zhí)行,因?yàn)樗赡苌婕矮@取和解碼媒體數(shù)據(jù)。因此,如同任何方法,可能需要很長(zhǎng)時(shí)間執(zhí)行,你不應(yīng)該從應(yīng)用程序的UI線程調(diào)用它。這樣做將導(dǎo)致UI掛到方法返回,這是一個(gè)非常糟糕的用戶體驗(yàn),也可能會(huì)引起應(yīng)用程序沒(méi)有響應(yīng)的錯(cuò)誤。即使你預(yù)期你的資源能快速加載,記住,任何超過(guò)十分之一秒的反應(yīng)在界面上會(huì)造成明顯的停頓,將導(dǎo)致給用戶的印象是:你的應(yīng)用程序是緩慢的。
為了避免你的UI線程掛起,產(chǎn)生另一個(gè)線程準(zhǔn)備MediaPlayer當(dāng)完成時(shí)通知主線程。你可以寫自己的線程的邏輯,框架提供prepareAsync()方法,方便的使用MediaPlayer。該方法在后臺(tái)開始準(zhǔn)備媒體并立即返回。當(dāng)媒體準(zhǔn)備好了,MediaPlayer.OnPreparedListener的onPrepared方法,通過(guò)配置setonpreparedlistener()方法來(lái)調(diào)用。
4.
狀態(tài)管理 - Managing State
關(guān)于MediaPlayer,你需要記住的另一點(diǎn)是它的狀態(tài)。即,在你編寫自己的代碼的時(shí)候,必須時(shí)刻意識(shí)到MediaPlayer有一個(gè)內(nèi)部狀態(tài),因?yàn)橹挥挟?dāng)玩家在特定狀態(tài),某些特定的操作才會(huì)有效。如果您在錯(cuò)誤的狀態(tài)執(zhí)行一個(gè)操作,系統(tǒng)可能會(huì)拋出一個(gè)異?;蛞鹌渌钊瞬豢斓男袨?。
MediaPlayer類里有文件顯示一個(gè)完整的狀態(tài)轉(zhuǎn)換圖,闡明哪些方法可以把MediaPlayer從一個(gè)狀態(tài)改變到另一個(gè)狀態(tài)。例如,當(dāng)您創(chuàng)建一個(gè)新的MediaPlayer,它就處于閑置狀態(tài)。這時(shí),你應(yīng)該調(diào)用android.net.Uri)setDataSource()方法來(lái)初始化它,把它設(shè)置為初始化狀態(tài)。然后,你必須使用prepare()方法或prepareAsync()方法。當(dāng)MediaPlayer準(zhǔn)備好了,它將進(jìn)入準(zhǔn)備狀態(tài),這就意味著你可以調(diào)用start()方法來(lái)播放媒體。另外,在狀態(tài)轉(zhuǎn)換圖上闡明了,你可以調(diào)用start(),pause()和seekTo()這些方法在Started,Paused和PlaybackCompleted狀態(tài)之間進(jìn)行轉(zhuǎn)換。如果您調(diào)用stop()方法,這時(shí)請(qǐng)注意,你需要再次準(zhǔn)備MediaPlayer,才可以再一次調(diào)用start()方法。
在編寫代碼與MediaPlayer對(duì)象交互時(shí),心里要隨時(shí)想著狀態(tài)轉(zhuǎn)換圖,因?yàn)閺腻e(cuò)誤的狀態(tài)調(diào)用它的方法,是引起錯(cuò)誤的常見原因。
釋放MediaPlayer-Releasing the MediaPlayer
MediaPlayer會(huì)消耗寶貴的系統(tǒng)資源。因此,你應(yīng)該經(jīng)常采取額外的預(yù)防措施來(lái)確保及時(shí)把不需要的MediaPlayer取消掉。您需要調(diào)用release()方法來(lái)確保系統(tǒng)分配給它的資源正確釋放。例如,您正在使用MediaPlayer,同時(shí),你的活動(dòng)調(diào)用onStop()方法,這時(shí)你必須釋放MediaPlayer,因?yàn)槟愕幕顒?dòng)并非與用戶交互,留著它沒(méi)什么意義(除非你是在后臺(tái)播放多媒體,這是下一節(jié)中將討論的內(nèi)容)。當(dāng)你的活動(dòng)恢復(fù)或者重新啟動(dòng),恢復(fù)播放之前,您需要?jiǎng)?chuàng)建一個(gè)新的MediaPlayer并且重新準(zhǔn)備。
下面是釋放和取消你的MediaPlayer的方法:
mediaPlayer.release();mediaPlayer = null;
作為思考題,考慮一下如果當(dāng)活動(dòng)停止的時(shí)候你忘了釋放MediaPlayer,活動(dòng)重啟后新建一個(gè)MediaPlayer,可能會(huì)發(fā)生的問(wèn)題。正如你可能知道的,當(dāng)用戶更改屏幕的方向(或以另一種方式更改設(shè)備配置),該系統(tǒng)通過(guò)重啟活動(dòng)處理(通過(guò)默認(rèn)方式),所以當(dāng)用戶頻繁在縱向和橫向之間切換時(shí),你可能會(huì)很快消耗掉所有的系統(tǒng)資源,原因是你沒(méi)有釋放方向變化時(shí)各個(gè)方向上創(chuàng)建的新MediaPlayer。(更多關(guān)于運(yùn)行時(shí)重啟的資料,請(qǐng)查看HandlingRuntime Changes)。
你可能會(huì)想知道在用戶離開活動(dòng)時(shí)后臺(tái)繼續(xù)播放媒體是如何實(shí)現(xiàn)的,采用同樣的方式實(shí)現(xiàn)的,如內(nèi)置的音樂(lè)應(yīng)用程序的行為。在這種情況下,你需要通過(guò)一個(gè)Service來(lái)控制MediaPlayer,所以我們開始學(xué)習(xí)Usinga Service with MediaPlayer。
5.
使用服務(wù)控制MediaPlayer - Using a Service with MediaPlayer
如果你希望后臺(tái)播放媒體,你希望用戶操作其他應(yīng)用時(shí)繼續(xù)播放,你必須開始一個(gè)Service并且從那里控制MediaPlayer實(shí)例。你必須慎重考慮這個(gè)設(shè)置,因?yàn)橛脩襞c系統(tǒng)期望應(yīng)用程序運(yùn)行的后臺(tái)服務(wù)應(yīng)該與系統(tǒng)的其余部分相互作用。如果應(yīng)用程序不滿足這些預(yù)期,就不能有良好的用戶體驗(yàn)。本節(jié)介紹的主要內(nèi)容是:告訴你相關(guān)知識(shí),并提供建議如何接觸它們。
異步運(yùn)行 - Running asynchronously
首先,如一個(gè)Activity,服務(wù)里的所有任務(wù)默認(rèn)在單一線程中完成。如果你從同一個(gè)應(yīng)用程序里運(yùn)行一個(gè)Activity和一個(gè)Service,它們默認(rèn)使用相同的線程(“主線程”)。因此,Service需要迅速處理傳入的意圖并且響應(yīng)它們的時(shí)候從不執(zhí)行冗長(zhǎng)的計(jì)算。如果預(yù)計(jì)調(diào)用一些復(fù)雜的任務(wù)或阻塞,你必須異步處理這些任務(wù):由另一個(gè)線程自己實(shí)現(xiàn)自己,或使用框架處理異步。
例如,當(dāng)你從主要線程使用一個(gè)MediaPlayer,你應(yīng)該調(diào)用prepareAsync()方法而不是prepare()方法,實(shí)現(xiàn)MediaPlayer.OnPreparedListener,以便當(dāng)你準(zhǔn)備工作完畢后,得到可以開始播放的通知。
代碼如下:
public class MyService extends Service implements MediaPlayer.OnPreparedListener
{ private static final ACTION_PLAY = "com.example.action.PLAY";MediaPlayer mMediaPlayer = null;
public int onStartCommand(Intent intent, int flags, int startId)
{ ... if (intent.getAction().equals(ACTION_PLAY)) { mMediaPlayer = ... // initialize it heremMediaPlayer.setOnPreparedListener(this);
mMediaPlayer.prepareAsync(); // prepare async to not block main thread
}
}
public void onPrepared(MediaPlayer player)
{ player.start();}}
處理異步錯(cuò)誤 - Handling asynchronous errors
在同步操作中,錯(cuò)誤通常會(huì)出現(xiàn)異常或錯(cuò)誤代碼信息。但當(dāng)你使用異步資源時(shí),您需要確保您的應(yīng)用程序有錯(cuò)誤提示,在MediaPlayer中,要做到這一點(diǎn),可以通過(guò)實(shí)現(xiàn)MediaPlayer.OnErrorListener,并且將它設(shè)置在你的MediaPlayer實(shí)體中。
public class MyService extends Service implements MediaPlayer.OnErrorListener { MediaPlayer mMediaPlayer; public void initMediaPlayer() { // ...initialize the MediaPlayer here... mMediaPlayer.setOnErrorListener(this); } @Override public boolean onError(MediaPlayer mp, int what, int extra) { // ... react appropriately ... // The MediaPlayer has moved to the Error state, must be reset! }}請(qǐng)牢記,當(dāng)出現(xiàn)錯(cuò)誤,將這個(gè)MediaPlayer設(shè)置為錯(cuò)誤狀態(tài)(請(qǐng)參考MediaPlayer類文檔的完整的狀態(tài)關(guān)系圖)您再次使用它之前,必須重置這個(gè)狀態(tài)。
使用喚醒鎖 - Using wake locks
應(yīng)用程序在后臺(tái)播放媒體,其服務(wù)在運(yùn)行期間,設(shè)備可能會(huì)進(jìn)入休眠狀態(tài)。因?yàn)锳ndroid系統(tǒng)希望在設(shè)備休眠時(shí)節(jié)省電池。系統(tǒng)試圖關(guān)閉手機(jī)的應(yīng)用程序,是沒(méi)有必要的,包括CPU和WiFi硬件。但是,如果你的服務(wù)正在運(yùn)行或播放著音樂(lè),你希望防止系統(tǒng)干擾你的回放。
為了確保您的服務(wù)在這些條件下能繼續(xù)運(yùn)行,你需要使用“wakelocks”。喚醒鎖是一種信號(hào)系統(tǒng),它發(fā)出信號(hào),顯示:應(yīng)用程序正在使用或可用的功能,或手機(jī)閑置。
注意:你應(yīng)該盡量少用喚醒鎖,只有在必要時(shí)候才使用它們。它們會(huì)使設(shè)備的電池壽命大大降低。
你MediaPlayer正在播放時(shí),需要確保CPU持續(xù)運(yùn)行,當(dāng)初始化你的MediaPlayer時(shí),調(diào)用setWakeMode()方法。一旦你這樣做了,當(dāng)暫?;蛲V箷r(shí)候,MediaPlayer持有指定的鎖:
mMediaPlayer = new MediaPlayer();// ... other initialization here ...mMediaPlayer.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);
在這個(gè)例子中獲得喚醒鎖是指在保證CPU在喚醒狀態(tài)。當(dāng)你通過(guò)網(wǎng)絡(luò)獲取媒體和您正在使用WiFi時(shí),你可能希望有個(gè)WifiLock,可以手動(dòng)獲取并釋放。當(dāng)你開始通過(guò)遠(yuǎn)程URL準(zhǔn)備MediaPlayer,你應(yīng)該創(chuàng)建并獲得wi- fi鎖。 代碼如下:
WifiLock wifiLock = ((WifiManager) getSystemService(Context.WIFI_SERVICE)) .createWifiLock(WifiManager.WIFI_MODE_FULL, "mylock"); wifiLock.acquire();
當(dāng)你暫?;蛲V鼓愕拿襟w時(shí),或當(dāng)你不再需要這樣的網(wǎng)絡(luò),你應(yīng)該釋放該鎖: 代碼如下:
wifiLock.release();
作為前景服務(wù)運(yùn)行 - Running as a foreground service
服務(wù)通常用于執(zhí)行后臺(tái)任務(wù),例如獲取電子郵件,同步數(shù)據(jù),下載內(nèi)容,或其他。在這些情況下,用戶不會(huì)意識(shí)到這個(gè)服務(wù)的執(zhí)行,甚至可能不會(huì)注意到這些服務(wù)被打斷,后來(lái)重新啟動(dòng)。毫無(wú)疑問(wèn),后臺(tái)播放音樂(lè)是一個(gè)服務(wù),用戶能意識(shí)到,任何中斷都會(huì)嚴(yán)重影響到用戶體驗(yàn)。此外,用戶可能會(huì)希望在這個(gè)服務(wù)執(zhí)行期間作用于它。這種情況,服務(wù)應(yīng)該運(yùn)行一個(gè)“前景服務(wù)”。前臺(tái)服務(wù)在系統(tǒng)中持有一個(gè)更高水平的重要性,系統(tǒng)幾乎從未將服務(wù)扼殺,因?yàn)樗鼘?duì)用戶有著直接的重要性。當(dāng)應(yīng)用在前臺(tái)運(yùn)行,該服務(wù)還必須提供一個(gè)狀態(tài)欄來(lái)通知用戶意識(shí)有服務(wù)正在運(yùn)行同時(shí)允許他們打開一個(gè)活動(dòng),可以與服務(wù)進(jìn)行交互。
為了把你的服務(wù)變?yōu)榍熬胺?wù),您必須為狀態(tài)欄創(chuàng)建一個(gè)Notification,并且從Service調(diào)用startForeground()方法。
代碼如下:
String songName;// assign the song name to songNamePendingIntent pi = PendingIntent.getActivity(getApplicationContext(), 0, new Intent(getApplicationContext(), MainActivity.class), PendingIntent.FLAG_UPDATE_CURRENT);Notification notification = new Notification();notification.tickerText = text;notification.icon = R.drawable.play0;notification.flags |= Notification.FLAG_ONGOING_EVENT;notification.setLatestEventInfo(getApplicationContext(), "MusicPlayerSample", "Playing: " + songName, pi);startForeground(NOTIFICATION_ID, notification);
通知區(qū)域可見的設(shè)備告訴你,服務(wù)在前臺(tái)運(yùn)行。如果用戶選擇了這個(gè)通知,系統(tǒng)將調(diào)用你提供的PendingIntent。在上面的例子中,它打開了一個(gè)Activity。(MainActivity)
圖1顯示了如何將通知呈現(xiàn)給用戶:
圖1:界面的一個(gè)前景服務(wù)通知,如上圖,顯示通知圖標(biāo)(在左)、擴(kuò)展視圖(在右)。
實(shí)際執(zhí)行一些用戶能夠意識(shí)到的服務(wù)時(shí),你應(yīng)該保留“foregroundservice”的狀態(tài)。相反情況下,你應(yīng)該調(diào)用stopForeground()方法來(lái)釋放它。 代碼如下:
stopForeground(true);
更多信息,請(qǐng)參考Service和StatusBar Notifications的相關(guān)文檔。
處理音頻焦點(diǎn) - Handling audio focus=
在給定的時(shí)間盡管只有一個(gè)活動(dòng)可以運(yùn)行,但Android是一個(gè)多任務(wù)環(huán)境。這對(duì)應(yīng)用程序使用音頻造成了一個(gè)特別大的難度,由于只有一個(gè)音頻輸出,可能會(huì)有好幾個(gè)媒體服務(wù)爭(zhēng)奪使用它。Android2.2之前,沒(méi)有內(nèi)置機(jī)制來(lái)解決這個(gè)問(wèn)題,這可能在某些情況下導(dǎo)致糟糕的用戶體驗(yàn)。例如,一個(gè)用戶正在聽音樂(lè),同時(shí),另一個(gè)應(yīng)用程序有很重要的事需要通知用戶,由于吵鬧的音樂(lè)用戶可能不會(huì)聽到提示音。從Android2.2開始,Android平臺(tái)為應(yīng)用程序提供了一個(gè)方式來(lái)協(xié)商設(shè)備的音頻輸出。這個(gè)機(jī)制被稱為音頻焦點(diǎn)。
當(dāng)您的應(yīng)用程序需要輸出音頻如音樂(lè)或一個(gè)通知,這時(shí)你就必須請(qǐng)求音頻焦點(diǎn)。一旦得到焦點(diǎn),它就可以自由的使用聲音輸出設(shè)備,同時(shí)它會(huì)不斷監(jiān)聽焦點(diǎn)的更改。如果它被通知已經(jīng)失去了音頻焦點(diǎn),它會(huì)要么立即殺死音頻或立即降低到一個(gè)安靜的水平(被稱為“ducking”——有一個(gè)標(biāo)記,指示哪一個(gè)是適當(dāng)?shù)模┊?dāng)它再次接收焦點(diǎn)時(shí),繼續(xù)不斷播放。
音頻焦點(diǎn)是自然的合作。應(yīng)用程序都期望(強(qiáng)烈鼓勵(lì))遵守音頻焦點(diǎn)指南,但規(guī)則并不是系統(tǒng)強(qiáng)制執(zhí)行的。如果應(yīng)用程序失去音頻焦點(diǎn)后想要播放嘈雜的音樂(lè),在系統(tǒng)中沒(méi)有什么會(huì)阻止他。然而,這樣可能會(huì)讓用戶有更糟糕的體驗(yàn),并可能卸載這運(yùn)行不當(dāng)?shù)膽?yīng)用程序。
請(qǐng)求音頻焦點(diǎn),您必須從AudioManager調(diào)用requestAudioFocus()方法,下面展示一個(gè)例子:
AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);int result = audioManager.requestAudioFocus(this, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);if (result!= AudioManager.AUDIOFOCUS_REQUEST_GRANTED) { // could not get audio focus.}requestAudioFocus()的第一個(gè)參數(shù)是AudioManager.OnAudioFocusChangeListener,每當(dāng)音頻焦點(diǎn)有變動(dòng)的時(shí)候其onAudioFocusChange()方法被調(diào)用。您還應(yīng)該在你的服務(wù)和活動(dòng)上實(shí)現(xiàn)這個(gè)接口。
代碼如下:
class MyService extends Service implements AudioManager.OnAudioFocusChangeListener { // .... public void onAudioFocusChange(int focusChange) { // Do something based on focus change... }}focusChange參數(shù)告訴你音頻焦點(diǎn)是如何改變的,并且可以使用以下的值之一(他們都是在AudioManager中定義常量的):
下面是一個(gè)示例實(shí)現(xiàn):
public void onAudioFocusChange(int focusChange) { switch (focusChange) { case AudioManager.AUDIOFOCUS_GAIN: // resume playback if (mMediaPlayer == null) initMediaPlayer(); else if (!mMediaPlayer.isPlaying()) mMediaPlayer.start(); mMediaPlayer.setVolume(1.0f, 1.0f); break; case AudioManager.AUDIOFOCUS_LOSS: // Lost focus for an unbounded amount of time: stop playback and release media player if (mMediaPlayer.isPlaying()) mMediaPlayer.stop(); mMediaPlayer.release(); mMediaPlayer = null; break; case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT: // Lost focus for a short time, but we have to stop // playback. We don't release the media player because playback // is likely to resume if (mMediaPlayer.isPlaying()) mMediaPlayer.pause(); break; case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK: // Lost focus for a short time, but it's ok to keep playing // at an attenuated level if (mMediaPlayer.isPlaying()) mMediaPlayer.setVolume(0.1f, 0.1f); break; }}記住,音頻焦點(diǎn)APIs在API級(jí)別8(Android2.2)及以上才有效。所以如果你想要支持的以前版本的Android,(如果有的話)你應(yīng)該采取一種向后兼容性策略,允許您使用該特性,(如果沒(méi)有的話),只能選擇8以后的版本。
通過(guò)反射調(diào)用音頻焦點(diǎn)方法或通過(guò)在一個(gè)單獨(dú)類中實(shí)現(xiàn)所有的音頻焦點(diǎn)特性,您可以實(shí)現(xiàn)向后兼容性(AudioFocusHelper中闡明)。下面是這樣一個(gè)類的示例:
public class AudioFocusHelper implements AudioManager.OnAudioFocusChangeListener { AudioManager mAudioManager; // other fields here, you'll probably hold a reference to an interface // that you can use to communicate the focus changes to your Service public AudioFocusHelper(Context ctx, ) { mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); // ... } public boolean requestFocus() { return AudioManager.AUDIOFOCUS_REQUEST_GRANTED == mAudioManager.requestAudioFocus(mContext, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN); } public boolean abandonFocus() { return AudioManager.AUDIOFOCUS_REQUEST_GRANTED == mAudioManager.abandonAudioFocus(this); } @Override public void onAudioFocusChange(int focusChange) { // let your service know about the focus change }}當(dāng)你發(fā)現(xiàn)系統(tǒng)運(yùn)行時(shí)API級(jí)別在8級(jí)或以上時(shí),您可以創(chuàng)建AudioFocusHelper類的一個(gè)實(shí)例,例如:
if (android.os.Build.VERSION.SDK_INT >= 8) { mAudioFocusHelper = new AudioFocusHelper(getApplicationContext(), this);} else { mAudioFocusHelper = null;}執(zhí)行清理 - Performing cleanup
正如前面所提到的,MediaPlayer對(duì)象會(huì)消耗大量的系統(tǒng)資源,所以你可以在你需要用他的時(shí)候保留他,當(dāng)你不需要他的時(shí)候調(diào)用release()方法。調(diào)用這個(gè)顯式地清除方法是重要的,而不是依賴于系統(tǒng)的垃圾收集,因?yàn)樗赡苄枰恍r(shí)間垃圾收集器才能收回MediaPlayer,因?yàn)檫@只是內(nèi)存敏感的需求而不是其他媒體資源的短缺。既然如此,當(dāng)你使用一個(gè)服務(wù)時(shí),你應(yīng)該覆蓋onDestroy()方法,來(lái)確定你的MediaPlayer釋放了。
代碼如下:
public class MyService extends Service { MediaPlayer mMediaPlayer; // ... @Override public void onDestroy() { if (mMediaPlayer!= null) mMediaPlayer.release(); }}你最好始終尋找其它機(jī)會(huì)來(lái)釋放你的MediaPlayer,關(guān)閉的時(shí)候就釋放掉。例如,如果你期望較長(zhǎng)的一段時(shí)間不能夠播放媒體(例如,失去音頻焦點(diǎn)后),你肯定得先釋放你現(xiàn)有的MediaPlayer,以后要用的時(shí)候再創(chuàng)建它。另一方面,如果你只希望停止播放很短的一段時(shí)間,你應(yīng)該盡量保留你的MediaPlayer,以免花費(fèi)時(shí)間重新創(chuàng)建和準(zhǔn)備一遍。
處理AUDIO_BECOMING_NOISY意圖 - Handling the AUDIO_BECOMING_NOISYIntent
許多編寫良好的應(yīng)用程序有以下特點(diǎn),當(dāng)一個(gè)事件導(dǎo)致音頻變得聒噪時(shí),自動(dòng)停止音頻播放。(通過(guò)外部揚(yáng)聲器輸出)。例如,一個(gè)用戶戴著耳機(jī)聽音樂(lè),可能會(huì)不小心切斷耳機(jī)和設(shè)備的鏈接。雖然,這種行為不會(huì)自動(dòng)發(fā)生。如果您沒(méi)有實(shí)現(xiàn)這個(gè)特性,設(shè)備的外部揚(yáng)聲器會(huì)將音頻播放出來(lái),這可能是用戶不希望發(fā)生的。
這些情況下通過(guò)處理ACTION_AUDIO_BECOMING_NOISY意圖,可以讓你的應(yīng)用程序停止播放音樂(lè),通過(guò)在你的manifest里添加以下代碼,你可以注冊(cè)一個(gè)接收器:
".MusicIntentReceiver"> "android.media.AUDIO_BECOMING_NOISY" />
注冊(cè)MusicIntentReceiver類當(dāng)作一個(gè)廣播接收器的意圖,然后您應(yīng)該實(shí)現(xiàn)這類,代碼如下:
public class MusicIntentReceiver implements android.content.BroadcastReceiver { @Override public void onReceive(Context ctx, Intent intent) { if (intent.getAction().equals( android.media.AudioManager.ACTION_AUDIO_BECOMING_NOISY)) { // signal your service to stop playback // (via an Intent, for instance) } }}從內(nèi)容解析器檢索媒體 - Retrieving Media from a Content Resolver
在媒體播放器應(yīng)用程序中,另一個(gè)可能有用的特性是用戶可以在設(shè)備上檢索音樂(lè)。你可以通過(guò)為外部媒體查詢ContentResolver,代碼如下:
ContentResolver contentResolver = getContentResolver();Uri uri = android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;Cursor cursor = contentResolver.query(uri, null, null, null, null);if (cursor == null) { // query failed, handle error.} else if (!cursor.moveToFirst()) { // no media on the device} else { int titleColumn = cursor.getColumnIndex(android.provider.MediaStore.Audio.Media.TITLE); int idColumn = cursor.getColumnIndex(android.provider.MediaStore.Audio.Media._ID); do { long thisId = cursor.getLong(idColumn); String thisTitle = cursor.getString(titleColumn); // ...process entry... } while (cursor.moveToNext());}要和MediaPlayer一起使用,你可以這樣做,代碼如下:
long id = ;Uri contentUri = ContentUris.withAppendedId( android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, id);mMediaPlayer = new MediaPlayer();mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);mMediaPlayer.setDataSource(getApplicationContext(), contentUri);// ...prepare and start...
愛(ài)華網(wǎng)本文地址 » http://www.klfzs.com/a/25101017/331121.html
愛(ài)華網(wǎng)



