MediaPlayer 總覽

Android 多媒體架構支援播放各種常見媒體類型, ,輕鬆將音訊、影片和圖片整合至應用程式中。你可以播放音訊或 影片取自儲存在應用程式資源 (原始資源) 中的媒體檔案 或是透過網路連線抵達的資料串流,全都使用 MediaPlayer API。

本文件說明如何使用 MediaPlayer:編寫媒體播放 與使用者和系統互動的應用程式。 愉快的使用者體驗另外 以便使用 ExoPlayer,而這是可自訂的開放原始碼軟體 支援 MediaPlayer 中未提供的高效能功能的程式庫

注意:您只能以標準輸出方式播放音訊資料 裝置。這是行動裝置喇叭或藍牙耳機。無法播放音效 檔案。

基本概念

下列類別可用來在 Android 架構中播放音效和影片:

MediaPlayer
此類別是播放音效和影片的主要 API。
AudioManager
這個類別可管理裝置上的音訊來源和音訊輸出。

資訊清單宣告

使用 MediaPlayer 開始開發應用程式前,請先確認您的資訊清單 取得適當聲明以允許使用相關功能。

  • 網際網路權限:如果您使用 MediaPlayer 串流網路內容 內容,您的應用程式必須要求網路存取權。
    <uses-permission android:name="android.permission.INTERNET" />
    
  • Wake Lock 權限 - 如果播放器應用程式需要保留螢幕 或使用 MediaPlayer.setScreenOnWhilePlaying()MediaPlayer.setWakeMode() 方法,您必須要求這項權限。
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    

使用 MediaPlayer

媒體架構中最重要的元素之一 MediaPlayer 類別此類別的物件可以擷取、解碼和播放音訊和影片 只需要最少設定這項功能支援多種不同的媒體來源,例如:

  • 本機資源
  • 內部 URI,例如您可從內容解析器取得的 URI
  • 外部網址 (串流)

如需 Android 支援的媒體格式清單 請參閱支援的媒體 「格式」頁面。

我們來看個例子 如何播放以本機原始資源 (儲存在應用程式的 res/raw/ 目錄):

Kotlin

var mediaPlayer = MediaPlayer.create(context, R.raw.sound_file_1)
mediaPlayer.start() // no need to call prepare(); create() does that for you

Java

MediaPlayer mediaPlayer = MediaPlayer.create(context, R.raw.sound_file_1);
mediaPlayer.start(); // no need to call prepare(); create() does that for you

在本例中,「原始」也就是系統 嘗試以任何特定方式剖析不過,這項資源的內容 原始音訊應該包含經過正確編碼和格式化的媒體檔案 均須具備支援格式

以下說明如何從系統本機提供的 URI 播放內容 (例如,您透過內容解析器取得):

Kotlin

val myUri: Uri = .... // initialize Uri here
val mediaPlayer = MediaPlayer().apply {
    setAudioAttributes(
        AudioAttributes.Builder()
            .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
            .setUsage(AudioAttributes.USAGE_MEDIA)
            .build()
    )
    setDataSource(applicationContext, myUri)
    prepare()
    start()
}

Java

Uri myUri = ....; // initialize Uri here
MediaPlayer mediaPlayer = new MediaPlayer();
mediaPlayer.setAudioAttributes(
    new AudioAttributes.Builder()
        .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
        .setUsage(AudioAttributes.USAGE_MEDIA)
        .build()
);
mediaPlayer.setDataSource(getApplicationContext(), myUri);
mediaPlayer.prepare();
mediaPlayer.start();

透過 HTTP 串流從遠端網址播放的步驟如下:

Kotlin

val url = "http://........" // your URL here
val mediaPlayer = MediaPlayer().apply {
    setAudioAttributes(
        AudioAttributes.Builder()
            .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
            .setUsage(AudioAttributes.USAGE_MEDIA)
            .build()
    )
    setDataSource(url)
    prepare() // might take long! (for buffering, etc)
    start()
}

Java

String url = "http://........"; // your URL here
MediaPlayer mediaPlayer = new MediaPlayer();
mediaPlayer.setAudioAttributes(
    new AudioAttributes.Builder()
        .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
        .setUsage(AudioAttributes.USAGE_MEDIA)
        .build()
);
mediaPlayer.setDataSource(url);
mediaPlayer.prepare(); // might take long! (for buffering, etc)
mediaPlayer.start();

注意: 如果您要傳遞網址以串流線上媒體檔案,則檔案必須具有 漸進式下載。

注意:您必須擷取或傳遞 IllegalArgumentExceptionIOException (使用時) setDataSource(),因為 您參照的檔案可能不存在。

非同步準備作業

MediaPlayer 的使用方式相當簡單 原則上不過請注意,還有更多事項 以便與一般 Android 應用程式正確整合適用對象 例如,對 prepare() 的呼叫 需要很長的時間來執行 則可能需要擷取並解碼媒體資料如同所有問題 方法可能需要很長的時間才能執行,但絕對不要從 應用程式的 UI 執行緒這會導致 UI 停止運作,直到方法傳回為止。 使用者體驗不佳,並可能導致 ANR (應用程式無回應) 錯誤。即使 您所預期資源能夠快速載入 請注意,只要多過十個參數 如果在 UI 回應的一秒內回應,就會造成明顯暫停,並 對應用程式速度緩慢的曝光使用者來說

為避免 UI 執行緒停止運作,請產生新的執行緒,以執行 準備 MediaPlayer,並在完成後通知主執行緒。不過, 您可以編寫執行緒邏輯 您自己,這個模式在使用 MediaPlayer 時十分常見 能讓您輕鬆完成工作。 prepareAsync() 方法。這個方法 開始在背景準備媒體並立即傳回。媒體 已準備完成,onPrepared() MediaPlayer.OnPreparedListener 方法,透過以下方式設定: 系統已呼叫 setOnPreparedListener()

管理狀態

您還應留意 MediaPlayer 的另一個層面: 是以狀態為基礎也就是說,MediaPlayer 具有內部狀態 您編寫程式碼時必須隨時留意,因為某些作業 只有在播放器處於特定狀態時,才算有效。如果您在載入資料集時 錯誤狀態時,系統可能會擲回例外狀況或造成其他不理想的行為。

MediaPlayer 類別會顯示完整的狀態圖表 ,說明哪些方法會將 MediaPlayer 從狀態移至其他狀態。 舉例來說,當您建立新的 MediaPlayer 時,它位於「Idle」中 時間。屆時,您應該呼叫 setDataSource(),享受 轉換為初始化狀態。之後,您必須使用 prepare()prepareAsync() 方法。時間 MediaPlayer 已完成準備,進入「Prepared」(準備) 這表示您可以呼叫 start() 讓它播放媒體正如這張圖表所示 您可以在「已開始」、「已暫停」和「播放已完成」狀態之間移動,方法是 呼叫這類方法 start(), pause()seekTo(), 來監控模型當您 但呼叫 stop() 時,請注意 除非您選擇,否則無法再次呼叫 start() 再次準備 MediaPlayer

請一律保留狀態圖表 編寫與容器相同的程式碼 MediaPlayer 物件,因為從錯誤狀態呼叫的方法是 常見的錯誤原因

發布 MediaPlayer

MediaPlayer 可以使用有價值的項目 系統資源 因此,請隨時採取額外的預防措施,確保 等候超過必要時間的 MediaPlayer 執行個體。當您 工作順利進行,建議您一律呼叫 release()可確保所有相關 分配給這個 Pod 的系統資源會正確釋出舉例來說 使用 MediaPlayer,您的活動會收到對 onStop() 的呼叫,因此您必須釋放 MediaPlayer。 因為這 在您的活動未與裝置互動時,保留一點意義也沒關係 使用者 (除非您是在背景播放媒體,詳情請參閱下一節)。 當然,恢復或重新啟動活動時,你需要 請建立新的 MediaPlayer 並再次準備,然後再繼續播放。

以下說明如何釋放 MediaPlayer,然後將其設為空值:

Kotlin

mediaPlayer?.release()
mediaPlayer = null

Java

mediaPlayer.release();
mediaPlayer = null;

舉例來說,假設 活動停止時忘記釋放 MediaPlayer,但會建立 等到活動再次開始時便會新的執行個體。如您所知,如果使用者變更 螢幕方向 (或者以其他方式變更裝置設定)、 根據預設,系統會重新啟動活動,因此您可以快速 並以使用者身分使用所有系統資源 會在直向和橫向之間來迴旋轉,因為 螢幕方向改變時,您會建立新的 MediaPlayer 版本。(如要進一步瞭解執行階段重新啟動,請參閱「處理執行階段變更」)。

你可能想知道是否要繼續玩 「背景媒體」就算使用者離開活動 系統就能正常啟動內建「音樂」應用程式的行為模式。在這種情況下,您需要具備的 服務控制的 MediaPlayer,如 會在下一節中介紹

在服務中使用 MediaPlayer

希望即使應用程式也能在背景中播放媒體 也就是您希望廣告在使用者處於離線狀態時繼續播放 與其他應用程式互動,您必須啟動 服務及管控 MediaPlayer 執行個體。 您需要將 在 MediaBrowserServiceCompat 服務中使用 MediaPlayer,並 並與 另一個活動中的MediaBrowserCompat

請務必謹慎處理用戶端/伺服器設定。員工可以達到 在背景服務中執行的玩家如何與其餘程式碼 有些人會將 Cloud Storage 視為檔案系統 但實際上不是如果您的應用程式不符合這些期望,使用者 使用體驗不佳已讀 建構音訊應用程式

本節說明在服務中實作 MediaPlayer 時,如何管理相關的特殊指示。

非同步執行

首先,就像 Activity 一樣 Service 是在單一執行緒中完成 在預設情況下,如果您透過同一個應用程式執行活動和服務, 根據預設,使用同一個執行緒 (「主要執行緒」)。因此,服務 快速處理傳入意圖 且一律不會在回應時執行冗長的運算。若有 工作或阻斷呼叫,就必須以非同步方式完成這些工作: 或您自行實作的其他執行緒,或使用該架構的眾多設施 以便進行非同步處理

舉例來說,透過主執行緒使用 MediaPlayer 時, 應呼叫 prepareAsync() prepare(),並實作 1 個MediaPlayer.OnPreparedListener ,以便在準備作業完成後收到通知。 例如:

Kotlin

private const val ACTION_PLAY: String = "com.example.action.PLAY"

class MyService: Service(), MediaPlayer.OnPreparedListener {

    private var mMediaPlayer: MediaPlayer? = null

    override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
        ...
        val action: String = intent.action
        when(action) {
            ACTION_PLAY -> {
                mMediaPlayer = ... // initialize it here
                mMediaPlayer?.apply {
                    setOnPreparedListener(this@MyService)
                    prepareAsync() // prepare async to not block main thread
                }

            }
        }
        ...
    }

    /** Called when MediaPlayer is ready */
    override fun onPrepared(mediaPlayer: MediaPlayer) {
        mediaPlayer.start()
    }
}

Java

public class MyService extends Service implements MediaPlayer.OnPreparedListener {
    private static final String ACTION_PLAY = "com.example.action.PLAY";
    MediaPlayer mediaPlayer = null;

    public int onStartCommand(Intent intent, int flags, int startId) {
        ...
        if (intent.getAction().equals(ACTION_PLAY)) {
            mediaPlayer = ... // initialize it here
            mediaPlayer.setOnPreparedListener(this);
            mediaPlayer.prepareAsync(); // prepare async to not block main thread
        }
    }

    /** Called when MediaPlayer is ready */
    public void onPrepared(MediaPlayer player) {
        player.start();
    }
}

處理非同步錯誤

執行同步作業時,錯誤通常會 但是當您透過非同步方式 請確保應用程式清楚顯示資源 錯誤。若是 MediaPlayer, 可以導入 「MediaPlayer.OnErrorListener」和 只要在 MediaPlayer 執行個體中設定這個虛擬機器即可:

Kotlin

class MyService : Service(), MediaPlayer.OnErrorListener {

    private var mediaPlayer: MediaPlayer? = null

    fun initMediaPlayer() {
        // ...initialize the MediaPlayer here...
        mediaPlayer?.setOnErrorListener(this)
    }

    override fun onError(mp: MediaPlayer, what: Int, extra: Int): Boolean {
        // ... react appropriately ...
        // The MediaPlayer has moved to the Error state, must be reset!
    }
}

Java

public class MyService extends Service implements MediaPlayer.OnErrorListener {
    MediaPlayer mediaPlayer;

    public void initMediaPlayer() {
        // ...initialize the MediaPlayer here...
        mediaPlayer.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!
    }
}

請特別注意,如果發生錯誤,MediaPlayer 就會進入「錯誤」狀態 (請參閱 完整狀態圖表的 MediaPlayer 類別) 而且必須重設才能再次使用

使用 Wake Lock

設計播放媒體的應用程式時 裝置可能會在背景進入休眠狀態 以及服務運作情形由於 Android 系統會盡可能 當裝置處於休眠狀態時,系統會嘗試關閉 具備的 這些元件包括 CPU 和 Wi-Fi 硬體。 不過,如果您的服務正在播放或串流播放音樂,您想要防止 避免系統幹擾您的播放

為了確保您的服務能繼續在 這些條件中,您就必須使用「Wake Lock」。Wake Lock 是一種向 應用程式使用的某些功能 仍可繼續使用。

注意:請務必謹慎使用 Wake Lock,並保持不動 這類功能會大幅降低 裝置。

確保 CPU 在 MediaPlayer 運作時仍可持續運作 初始化 MediaPlayer 時,請呼叫 setWakeMode() 方法。完成後 MediaPlayer 會在播放時保留指定的鎖定,並釋放鎖定 暫停或停止時:

Kotlin

mediaPlayer = MediaPlayer().apply {
    // ... other initialization here ...
    setWakeMode(applicationContext, PowerManager.PARTIAL_WAKE_LOCK)
}

Java

mediaPlayer = new MediaPlayer();
// ... other initialization here ...
mediaPlayer.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);

但是,此範例中取得的 Wake Lock 只能確保 CPU 保持清醒。如果 你是透過 而且你使用的是 Wi-Fi 連線 WifiLock 為 這意味著您必須手動取得和發布新版本當您開始準備 使用遠端網址 MediaPlayer,您應該建立及取得 Wi-Fi 鎖定。 例如:

Kotlin

val wifiManager = getSystemService(Context.WIFI_SERVICE) as WifiManager
val wifiLock: WifiManager.WifiLock =
    wifiManager.createWifiLock(WifiManager.WIFI_MODE_FULL, "mylock")

wifiLock.acquire()

Java

WifiLock wifiLock = ((WifiManager) getSystemService(Context.WIFI_SERVICE))
    .createWifiLock(WifiManager.WIFI_MODE_FULL, "mylock");

wifiLock.acquire();

您暫停或停止播放媒體,或不再需要使用 您應該解除鎖定:

Kotlin

wifiLock.release()

Java

wifiLock.release();

執行清除作業

如先前所述,MediaPlayer 物件可能會耗用大量資源 因此建議您只在需要時 使用完畢時為 release()。這很重要 來明確呼叫這個清理方法,而非依賴系統垃圾收集,因為 垃圾收集器可能需要一些時間才能收回 MediaPlayer 因為只適用於記憶體需求,也不會影響其他媒體相關資源。 因此,在使用服務時,請一律覆寫 onDestroy() 方法,確保您 MediaPlayer

Kotlin

class MyService : Service() {

    private var mediaPlayer: MediaPlayer? = null
    // ...

    override fun onDestroy() {
        super.onDestroy()
        mediaPlayer?.release()
    }
}

Java

public class MyService extends Service {
   MediaPlayer mediaPlayer;
   // ...

   @Override
   public void onDestroy() {
       super.onDestroy();
       if (mediaPlayer != null) mediaPlayer.release();
   }
}

建議你隨時尋找其他釋出 MediaPlayer 的機會 以及關機時一併釋出空間舉例來說 使用者長時間播放媒體 (例如失去音訊焦點後) 請務必發布現有的 MediaPlayer,然後再次建立 每月中的特定幾天 另一方面,如果您預期在很短的時間內停止播放 保留你的MediaPlayer,免除建立和準備檔案的負擔 可以選取「重新建立」,再次生成新的提示

數位版權管理 (DRM)

從 Android 8.0 (API 級別 26) 開始,MediaPlayer 包含會執行以下動作的 API: 支援播放受 DRM 保護的素材。與 MediaDrm,但它們以更高層級運作,且不在 會公開基礎的擷取器、drm 和加密物件

雖然 MediaPlayer DRM API 並未提供 MediaDrm,可支援最常見的用途。 目前的實作可處理下列內容類型:

  • 受 Widevine 保護的本機媒體檔案
  • 受 Widevine 保護的遠端/串流媒體檔案

以下程式碼片段示範如何使用新版 DRM MediaPlayer 方法。

如要管理 DRM 控制的媒體,您需要一併加入新方法和 MediaPlayer 呼叫的一般流程,如下所示:

Kotlin

mediaPlayer?.apply {
    setDataSource()
    setOnDrmConfigHelper() // optional, for custom configuration
    prepare()
    drmInfo?.also {
        prepareDrm()
        getKeyRequest()
        provideKeyResponse()
    }

    // MediaPlayer is now ready to use
    start()
    // ...play/pause/resume...
    stop()
    releaseDrm()
}

Java

setDataSource();
setOnDrmConfigHelper(); // optional, for custom configuration
prepare();
if (getDrmInfo() != null) {
  prepareDrm();
  getKeyRequest();
  provideKeyResponse();
}

// MediaPlayer is now ready to use
start();
// ...play/pause/resume...
stop();
releaseDrm();

首先請初始化 MediaPlayer 物件和設定 使用 setDataSource() 接著,如要使用數位著作權管理功能,請執行下列步驟:

  1. 如果您希望應用程式執行自訂設定,請定義 OnDrmConfigHelper 介面,並附加至 使用 setOnDrmConfigHelper()
  2. 呼叫 prepare()
  3. 呼叫 getDrmInfo()。如果來源有數位著作權管理 此方法會傳回非空值 MediaPlayer.DrmInfo 的值。

如果 MediaPlayer.DrmInfo 存在:

  1. 查看可用 UUID 的地圖,並選擇其中一個。
  2. 呼叫 prepareDrm() 為目前的來源準備 DRM 設定。
    • 如果您在帳單帳戶建立並註冊 OnDrmConfigHelper 回呼,則系統會呼叫 prepareDrm() 時 正在執行以便執行 DRM 的自訂設定 再開啟 DRM 工作階段。系統會呼叫回呼 同步執行呼叫 prepareDrm()。目的地: 存取 DRM 屬性 「getDrmPropertyString()」和 setDrmPropertyString()。 請避免執行耗時較長的作業。
    • 如果裝置尚未佈建 還有 prepareDrm() 人 會存取佈建伺服器佈建裝置。這可能需要 視網路連線狀況而定,所需時間會有所不同。
  3. 如要取得不透明的金鑰要求位元組陣列並傳送至授權伺服器,請呼叫 getKeyRequest()
  4. 如要將授權伺服器收到的金鑰回應通知 DRM 引擎,請呼叫 provideKeyResponse()。結果取決於金鑰要求類型:
    • 如果是用於離線金鑰要求的回應,結果會是金鑰組 ID。別擔心!您可以使用 這個金鑰組 ID 與 restoreKeys() 可將金鑰還原至新的 會很有幫助
    • 如果是串流或發布要求的回應,結果為空值。

以非同步方式執行 prepareDrm()

根據預設,prepareDrm() 系統會同步執行,並在準備完成前進行封鎖。不過 首次在新裝置上進行 DRM 準備作業時,可能也需要佈建, 內部處理的 prepareDrm()和 網路作業涉及網路作業,因此可能需要一點時間才能完成。你可以 避免封鎖 prepareDrm() 製作者 定義及設定 MediaPlayer.OnDrmPreparedListener

設定 OnDrmPreparedListener 時, prepareDrm() 會視需要在背景執行佈建及準備作業。時間 佈建和準備作業完成後,就會呼叫事件監聽器。請 不對 接聽程式就會執行 (除非透過處理常式執行緒註冊監聽器)。 呼叫事件監聽器前後可以 prepareDrm() 就會傳回值。

以非同步方式設定 DRM

只要建立並註冊 MediaPlayer.OnDrmInfoListener,用於進行 DRM 準備,以及 MediaPlayer.OnDrmPreparedListener 鍵啟動播放器。 因此,只要使用 prepareAsync(),如下所示:

Kotlin

setOnPreparedListener()
setOnDrmInfoListener()
setDataSource()
prepareAsync()
// ...

// If the data source content is protected you receive a call to the onDrmInfo() callback.
override fun onDrmInfo(mediaPlayer: MediaPlayer, drmInfo: MediaPlayer.DrmInfo) {
    mediaPlayer.apply {
        prepareDrm()
        getKeyRequest()
        provideKeyResponse()
    }
}

// When prepareAsync() finishes, you receive a call to the onPrepared() callback.
// If there is a DRM, onDrmInfo() sets it up before executing this callback,
// so you can start the player.
override fun onPrepared(mediaPlayer: MediaPlayer) {
    mediaPlayer.start()
}

Java

setOnPreparedListener();
setOnDrmInfoListener();
setDataSource();
prepareAsync();
// ...

// If the data source content is protected you receive a call to the onDrmInfo() callback.
onDrmInfo() {
  prepareDrm();
  getKeyRequest();
  provideKeyResponse();
}

// When prepareAsync() finishes, you receive a call to the onPrepared() callback.
// If there is a DRM, onDrmInfo() sets it up before executing this callback,
// so you can start the player.
onPrepared() {

start();
}

處理加密媒體

從 Android 8.0 (API 級別 26) MediaPlayer 開始,也可以解密 常見加密配置 (CENC) 和 基本串流類型的 HLS 樣本層級加密媒體 (METHOD=SAMPLE-AES) H.264 和 AAC之前支援完整區隔加密媒體 (METHOD=AES-128)。

從 ContentResolver 擷取媒體

媒體播放器應用程式還有另一項實用功能 擷取使用者在裝置上的音樂。方法是查詢 ContentResolver 以取得外部媒體:

Kotlin

val resolver: ContentResolver = contentResolver
val uri = android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
val cursor: Cursor? = resolver.query(uri, null, null, null, null)
when {
    cursor == null -> {
        // query failed, handle error.
    }
    !cursor.moveToFirst() -> {
        // no media on the device
    }
    else -> {
        val titleColumn: Int = cursor.getColumnIndex(android.provider.MediaStore.Audio.Media.TITLE)
        val idColumn: Int = cursor.getColumnIndex(android.provider.MediaStore.Audio.Media._ID)
        do {
            val thisId = cursor.getLong(idColumn)
            val thisTitle = cursor.getString(titleColumn)
            // ...process entry...
        } while (cursor.moveToNext())
    }
}
cursor?.close()

Java

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 搭配使用,您可以:

Kotlin

val id: Long = /* retrieve it from somewhere */
val contentUri: Uri =
    ContentUris.withAppendedId(android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, id )

mediaPlayer = MediaPlayer().apply {
    setAudioAttributes(
        AudioAttributes.Builder()
            .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
            .setUsage(AudioAttributes.USAGE_MEDIA)
            .build()
    )
    setDataSource(applicationContext, contentUri)
}

// ...prepare and start...

Java

long id = /* retrieve it from somewhere */;
Uri contentUri = ContentUris.withAppendedId(
        android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, id);

mediaPlayer = new MediaPlayer();
mediaPlayer.setAudioAttributes(
    new AudioAttributes.Builder()
        .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
        .setUsage(AudioAttributes.USAGE_MEDIA)
        .build()
);
mediaPlayer.setDataSource(getApplicationContext(), contentUri);

// ...prepare and start...

瞭解詳情

下列頁面說明與錄製、儲存和播放音訊及視訊相關的主題。