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应该也会出现一样的问题。

写的比较杂乱简单,但愿可以帮助到碰到一样问题的人。

相关文章
相关标签/搜索