Flutter audioplayers使用小結

簡介

audioplayers是一個能夠支持同時播放多個音頻文件的Flutter的庫。用法也是至關的簡單:ios

AudioPlayer audioPlayer = new AudioPlayer();
 await audioPlayer.play(url);

 //or
 //await audioPlayer.play(localPath, isLocal: true);
 
 
 // 一些控制API
 await audioPlayer.pause();
 await audioPlayer.stop();
 await audioPlayer.resume();
複製代碼

如何使程序崩潰(Android)

AudioPlayer audioPlayer = new AudioPlayer();
await audioPlayer.play(localPath, isLocal: true);

//播放後,立刻調用暫停,底層拋出`PlatformException`異常,程序崩潰
await audioPlayer.pause();

複製代碼

嗯,就是這麼簡單,還沒寫滿10行代碼就GG了。git

分析緣由

遇到了這個崩潰後,本人也是懷揣着好奇心第一時間翻看了audioplayers的代碼,以及又看了一遍文檔。原來,文檔中介紹,爲了實現先加載後播放的功能,咱們能夠調用audioPlayer.setUrl函數,以後須要播放時候調用resume進行播放便可。github

嗯,當時我沒看到這段,因禍得福焉知非福,這樣的實現也是一樣存在問題的。 先來一張Android MediaPlayerState Diagram:異步

不管是audioPlayer.play仍是andioPlayer.setUrl,他們最重要的工做就是調用Android原生的prepareAsync方法,讓MediaPlayer對象處於Prepared狀態。引用一下Android官方文檔:async

A MediaPlayer object must first enter the Prepared state before playback can be started.函數

...... or a call to prepareAsync() (asynchronous) which first transfers the object to the Preparing state after the call returns (which occurs almost right away) while the internal player engine continues working on the rest of preparation work until the preparation work completes. When the preparation completes or when prepare() call returns, the internal player engine then calls a user supplied callback method ......lua

歸納起來就兩點:url

  1. 播放/暫停等操做以前,必須進入Prepared狀態
  2. prepareAsync是一個異步操做,會使MediaPlayer進入preparing狀態, 當底層的player engine完成preparation的工做時,將會調用用戶提供的回調函數。

因此,上面崩潰的問題也比較明瞭了,audioPlayer.play調用以後底層的MediaPlayer實際上是一個preparing狀態,此時調用pause致使了PlatformException異常的拋出,程序直接崩潰。這實際上是一個audioplayers沒有處理好的狀態,playsetUrl這類的Future不該該只在perparing狀態就resolve,而應該等到preparedspa

所以...我反手去audioplayers github上提了個issue,深藏功與名。3d

尾聲

audioplayersAndroid還支持SoundPool(new AudioPlayer(mode: PlayerMode.LOW_LATENCY)),也存在着一樣的問題。

推測ios應該也會出現一樣的問題。

寫的比較雜亂簡單,但願可以幫助到碰到一樣問題的人。

相關文章
相關標籤/搜索