Android Vitamio和ExoPlayer两种播放器优劣分析
作者:高林雨露
Vitamio是一个功能强大而稳定的播放器库,它支持多种视频格式和编解码方式,并且具有快速、流畅的播放效果,因此在一些对播放质量要求比较高的应用场景下可以考虑使用。但是需要注意的是,Vitamio的开发团队近些年来已经较少更新和维护,不支持较新的Android版本(如Android 7.0及以上版本),因此在一些需要支持最新Android版本的应用中,可能需要考虑其他选项。
ExoPlayer是Google推出的一个功能强大的播放器库,它支持多种视频格式和编解码方式,具有良好的扩展性和定制性,可以通过插件等方式支持更多的功能和数据源。与Vitamio相比,ExoPlayer的开发团队更新迭代更为频繁,并且具有良好的Google生态环境(如与Android Studio的良好兼容等),因此在一些需要开发更加灵活、定制化的应用中,可以优先考虑使用。
总之,Vitamio和ExoPlayer都是非常优秀的播放器库,具体使用哪一个要根据你的实际需求来选择。如果你的应用比较老,需要支持7.0以下的Android版本,那么可以考虑使用Vitamio;如果你需要开发更加灵活、定制化的播放器,那么可以考虑使用ExoPlayer。
ExoPlayer支持音频播放。事实上,ExoPlayer可以用于播放视频、音频和流媒体等多种媒体格式。由于其良好的架构设计和强大的扩展性,ExoPlayer可以通过插件等方式支持更多的格式和功能,满足不同应用场景下的需求。
如果你需要使用ExoPlayer进行音频播放,可以通过以下步骤进行操作:
- 添加ExoPlayer库依赖,可以通过Gradle等方式进行添加。
- 创建一个SimpleExoPlayer对象,并设置数据源。
- 通过SimpleExoPlayer对象进行播放控制,包括播放、暂停、停止、音量控制等操作。
示例代码如下:
// 添加ExoPlayer库依赖 implementation 'com.google.android.exoplayer:exoplayer-core:2.14.1' // 创建SimpleExoPlayer对象 SimpleExoPlayer player = new SimpleExoPlayer.Builder(context).build(); MediaItem mediaItem = MediaItem.fromUri(audioUri); player.setMediaItem(mediaItem); // 进行播放控制 player.prepare(); player.play();
需要注意的是,这只是一个简单的音频播放示例,实际使用中可能需要更复杂的逻辑处理,例如错误处理、缓冲控制等。另外,需要根据实际需求选择合适的数据源类型、音频编码等参数。
进一步封装ExoPlayer使用:
对于ExoPlayer的使用,我们可以进行一些进一步的封装,将ExoPlayer的初始化、播放等操作封装在一个类里,便于在整个应用程序中使用。
封装需要考虑以下几个方面:
- 简单易用:封装的类和接口应该易于理解和使用,不需要过多的配置和参数即可完成基本的操作。
- 错误处理:封装的类应该能够处理各种错误情况,并且提供相应的错误回调或异常机制,方便使用者进行错误处理和调试。
- 状态管理:封装的类应该能够管理ExoPlayer的播放状态和进度,能够提供相应的状态回调,方便使用者进行状态变化的处理和UI更新。
- 可扩展性:封装的类应该具备可扩展性,能够满足使用者的各种需求,如添加播放列表、支持不同的媒体源等。
以下是一个完美封装的示例:
public class AudioPlayer implements Player.EventListener { private SimpleExoPlayer player; private PlayerStateListener playerStateListener; private Context context; private Uri currentUri; private boolean playWhenReady = true; // 播放器状态回调接口 public interface PlayerStateListener { void onPlayerStateChanged(boolean playWhenReady, int playbackState); void onPositionUpdated(long position, long duration); void onError(ExoPlaybackException error); } // 初始化操作,在Activity或Fragment中调用 public void init(Context context, Uri uri) { this.context = context; this.currentUri = uri; player = new SimpleExoPlayer.Builder(context).build(); player.setMediaItem(MediaItem.fromUri(uri)); player.addListener(this); player.prepare(); } // 播放操作 public void play() { if (player != null) { player.setPlayWhenReady(playWhenReady); } } // 暂停操作 public void pause() { if (player != null) { player.setPlayWhenReady(false); } } // 停止操作 public void stop() { if (player != null) { player.stop(); } } // 释放操作,在Activity或Fragment销毁时调用 public void release() { if (player != null) { player.release(); player.removeListener(this); player = null; } } // 设置播放状态回调接口 public void setPlayerStateListener(PlayerStateListener listener) { this.playerStateListener = listener; } // 获取当前播放的媒体源Uri public Uri getCurrentUri() { return currentUri; } // 获取当前播放状态和播放进度 public void getCurrentPosition() { if (player != null) { long position = player.getCurrentPosition(); long duration = player.getDuration(); if (playerStateListener != null) { playerStateListener.onPositionUpdated(position, duration); } } } // Player.EventListener 事件回调方法 @Override public void onPlayerStateChanged(boolean playWhenReady, int playbackState) { this.playWhenReady = playWhenReady; if (playerStateListener != null) { playerStateListener.onPlayerStateChanged(playWhenReady, playbackState); } } // Player.EventListener 事件回调方法 @Override public void onPlayerError(ExoPlaybackException error) { if (playerStateListener != null) { playerStateListener.onError(error); } } }
这个示例封装了ExoPlayer的初始化、播放、暂停、停止和释放等操作,可以在应用程序中方便地调用。使用时,只需要创建一个AudioPlayer对象,然后调用相应的方法即可。还有以下几个功能:
- 增加了播放器状态回调接口,方便使用者进行状态变化的处理和UI更新。
- 增加了获取当前播放进度和媒体源Uri的方法,方便使用者进行状态显示和媒体源管理。
- 实现了ExoPlayer的Player.EventListener回调接口,方便使用者进行错误处理和调试。
这个封装示例可能仍然不是完美的,但是对于大多数应用程序的使用场景已经足够成熟。如果需要更加复杂的功能,可以根据实际需。
在使用这个封装类的时候,你需要按以下步骤进行:
在你的Activity或Fragment中创建一个AudioPlayer实例,例如:
private AudioPlayer audioPlayer;
2.在创建完AudioPlayer实例后,调用init方法初始化。
audioPlayer = new AudioPlayer(); audioPlayer.init(this, Uri.parse("https://example.com/audio.mp3"));
其中,第一个参数传入当前的Context,第二个参数传入媒体源的Uri。
3.在需要播放的时候,调用play方法:
audioPlayer.play();
4.如果需要暂停播放,调用pause方法:
audioPlayer.pause();
5.如果需要停止播放,调用stop方法:
audioPlayer.stop();
6.如果需要释放播放器实例,取消实例化,调用release方法:
audioPlayer.release();
7.如果需要监听播放器状态回调,可以通过setPlayerStateListener方法来设置:
audioPlayer.setPlayerStateListener(new AudioPlayer.PlayerStateListener() { @Override public void onPlayerStateChanged(boolean playWhenReady, int playbackState) { // do something } @Override public void onPositionUpdated(long position, long duration) { // do something } @Override public void onError(ExoPlaybackException error) { // do something } });
8.如果需要获取当前播放进度和媒体源Uri,可以调用getCurrentPosition和getCurrentUri方法:
Uri uri = audioPlayer.getCurrentUri(); audioPlayer.getCurrentPosition();
以上就是大致的调用步骤,具体情况可以根据自己的场景进行调整。
public class AudioPlayer { private static final String TAG = AudioPlayer.class.getSimpleName(); private Context context; private SimpleExoPlayer player; private boolean isPlaying; private int currentPosition; private List < Integer > audioList; private List < OnProgressListener > progressListeners = new ArrayList < > (); private List < OnErrorListener > errorListeners = new ArrayList < > (); public AudioPlayer(Context context) { this.context = context; } public void init() { TrackSelector trackSelector = new DefaultTrackSelector(); player = new SimpleExoPlayer.Builder(context) .setTrackSelector(trackSelector) .build(); player.addListener(new Player.EventListener() { @Override public void onPlayerStateChanged(boolean playWhenReady, int playbackState) { switch (playbackState) { case Player.STATE_IDLE: Log.d(TAG, "onPlayerStateChanged: STATE_IDLE"); break; case Player.STATE_BUFFERING: Log.d(TAG, "on case Player.STATE_ENDED: Log.d(TAG, "onPlayerStateChanged: STATE_ENDED"); isPlaying = false; break; default: break; } } @Override public void onPlayerError(ExoPlaybackException error) { Log.e(TAG, "onPlayerError: " + error.getMessage()); for (OnErrorListener listener: errorListeners) { listener.onError(error); } release(); } }); player.addAnalyticsListener(new AnalyticsListener() { @Override public void onPositionDiscontinuity( AnalyticsListener.EventTime eventTime, int reason) { Log.d(TAG, "onPositionDiscontinuity"); if (player.getPlaybackError() != null) { Log.e(TAG, "onPlayerError: " + player.getPlaybackError().getMessage()); for (OnErrorListener listener: errorListeners) { listener.onError(player.getPlaybackError().getCause()); } release(); } currentPosition = player.getCurrentWindowIndex(); int duration = (int) player.getDuration(); int currentPosition = (int) player.getCurrentPosition(); for (OnProgressListener listener: progressListeners) { listener.onProgress(currentPosition, duration); } } }); } public void addOnErrorListener(OnErrorListener listener) { errorListeners.add(listener); } public void addOnProgressListener(OnProgressListener listener) { progressListeners.add(listener); } public void setAudioList(List < Integer > audioList) { this.audioList = audioList; } public void play(int position) { if (audioList == null || audioList.size() == 0) { return; } currentPosition = position; Uri audioUri = RawResourceDataSource.buildRawResourceUri(audioList.get(currentPosition)); MediaSource audioSource = new ProgressiveMediaSource.Factory( new DefaultDataSourceFactory(context, "ExoplayerDemo") ).createMediaSource(audioUri); player.prepare(audioSource); player.setPlayWhenReady(true); isPlaying = true; } public void pause() { if (player != null) { player.setPlayWhenReady(false); isPlaying = false; } } public void resume() { if (player != null) { player.setPlayWhenReady(true); isPlaying = true; } } public void stop() { if (player != null) { player.stop(); isPlaying = false; } } public void release() { if (player != null) { player.release(); player = null; isPlaying = false; } } public boolean isPlaying() { return isPlaying; } public int getCurrentPosition() { return currentPosition; } public interface OnProgressListener { void onProgress(int currentPosition, int duration); } public interface OnErrorListener { void onError(Exception e); } }
在以上代码中,我们添加了两个接口,OnProgressListener是用来监听进度的,OnErrorListener是用来监听播放异常的。在init方法中,我们给player对象添加了Player.EventListener接口和AnalyticsListener接口,分别用来监听播放状态的变化和进度的变化。播放异常包括播放开始前的异常和播放过程中的异常。在onPlaybackError方法中,我们回调OnErrorListener接口的onError方法。注意,在捕获到播放异常时,我们要调用release方法释放资源。
最后,通过调用addOnErrorListener和addOnProgressListener方法,我们可以将外部传进来的OnErrorListener和OnProgressListener实例添加到AudioPlayer类中。这样,在播放过程中,我们就可以监听到错误和进度的变化了。
至此,我们已经完整地实现了一个支持播放暂停、恢复、停止、进度和错误监听的AudioPlayer类。
到此这篇关于Android Vitamio和ExoPlayer两种播放器优劣分析的文章就介绍到这了,更多相关Android Vitamio和ExoPlayer内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!