Android Vitamio和ExoPlayer兩種播放器優(yōu)劣分析
Vitamio是一個功能強大而穩(wěn)定的播放器庫,它支持多種視頻格式和編解碼方式,并且具有快速、流暢的播放效果,因此在一些對播放質(zhì)量要求比較高的應(yīng)用場景下可以考慮使用。但是需要注意的是,Vitamio的開發(fā)團隊近些年來已經(jīng)較少更新和維護,不支持較新的Android版本(如Android 7.0及以上版本),因此在一些需要支持最新Android版本的應(yīng)用中,可能需要考慮其他選項。
ExoPlayer是Google推出的一個功能強大的播放器庫,它支持多種視頻格式和編解碼方式,具有良好的擴展性和定制性,可以通過插件等方式支持更多的功能和數(shù)據(jù)源。與Vitamio相比,ExoPlayer的開發(fā)團隊更新迭代更為頻繁,并且具有良好的Google生態(tài)環(huán)境(如與Android Studio的良好兼容等),因此在一些需要開發(fā)更加靈活、定制化的應(yīng)用中,可以優(yōu)先考慮使用。
總之,Vitamio和ExoPlayer都是非常優(yōu)秀的播放器庫,具體使用哪一個要根據(jù)你的實際需求來選擇。如果你的應(yīng)用比較老,需要支持7.0以下的Android版本,那么可以考慮使用Vitamio;如果你需要開發(fā)更加靈活、定制化的播放器,那么可以考慮使用ExoPlayer。
ExoPlayer支持音頻播放。事實上,ExoPlayer可以用于播放視頻、音頻和流媒體等多種媒體格式。由于其良好的架構(gòu)設(shè)計和強大的擴展性,ExoPlayer可以通過插件等方式支持更多的格式和功能,滿足不同應(yīng)用場景下的需求。
如果你需要使用ExoPlayer進行音頻播放,可以通過以下步驟進行操作:
- 添加ExoPlayer庫依賴,可以通過Gradle等方式進行添加。
- 創(chuàng)建一個SimpleExoPlayer對象,并設(shè)置數(shù)據(jù)源。
- 通過SimpleExoPlayer對象進行播放控制,包括播放、暫停、停止、音量控制等操作。
示例代碼如下:
// 添加ExoPlayer庫依賴 implementation 'com.google.android.exoplayer:exoplayer-core:2.14.1' // 創(chuàng)建SimpleExoPlayer對象 SimpleExoPlayer player = new SimpleExoPlayer.Builder(context).build(); MediaItem mediaItem = MediaItem.fromUri(audioUri); player.setMediaItem(mediaItem); // 進行播放控制 player.prepare(); player.play();
需要注意的是,這只是一個簡單的音頻播放示例,實際使用中可能需要更復(fù)雜的邏輯處理,例如錯誤處理、緩沖控制等。另外,需要根據(jù)實際需求選擇合適的數(shù)據(jù)源類型、音頻編碼等參數(shù)。
進一步封裝ExoPlayer使用:
對于ExoPlayer的使用,我們可以進行一些進一步的封裝,將ExoPlayer的初始化、播放等操作封裝在一個類里,便于在整個應(yīng)用程序中使用。
封裝需要考慮以下幾個方面:
- 簡單易用:封裝的類和接口應(yīng)該易于理解和使用,不需要過多的配置和參數(shù)即可完成基本的操作。
- 錯誤處理:封裝的類應(yīng)該能夠處理各種錯誤情況,并且提供相應(yīng)的錯誤回調(diào)或異常機制,方便使用者進行錯誤處理和調(diào)試。
- 狀態(tài)管理:封裝的類應(yīng)該能夠管理ExoPlayer的播放狀態(tài)和進度,能夠提供相應(yīng)的狀態(tài)回調(diào),方便使用者進行狀態(tài)變化的處理和UI更新。
- 可擴展性:封裝的類應(yīng)該具備可擴展性,能夠滿足使用者的各種需求,如添加播放列表、支持不同的媒體源等。
以下是一個完美封裝的示例:
public class AudioPlayer implements Player.EventListener {
private SimpleExoPlayer player;
private PlayerStateListener playerStateListener;
private Context context;
private Uri currentUri;
private boolean playWhenReady = true;
// 播放器狀態(tài)回調(diào)接口
public interface PlayerStateListener {
void onPlayerStateChanged(boolean playWhenReady, int playbackState);
void onPositionUpdated(long position, long duration);
void onError(ExoPlaybackException error);
}
// 初始化操作,在Activity或Fragment中調(diào)用
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銷毀時調(diào)用
public void release() {
if (player != null) {
player.release();
player.removeListener(this);
player = null;
}
}
// 設(shè)置播放狀態(tài)回調(diào)接口
public void setPlayerStateListener(PlayerStateListener listener) {
this.playerStateListener = listener;
}
// 獲取當(dāng)前播放的媒體源Uri
public Uri getCurrentUri() {
return currentUri;
}
// 獲取當(dāng)前播放狀態(tài)和播放進度
public void getCurrentPosition() {
if (player != null) {
long position = player.getCurrentPosition();
long duration = player.getDuration();
if (playerStateListener != null) {
playerStateListener.onPositionUpdated(position, duration);
}
}
}
// Player.EventListener 事件回調(diào)方法
@Override
public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
this.playWhenReady = playWhenReady;
if (playerStateListener != null) {
playerStateListener.onPlayerStateChanged(playWhenReady, playbackState);
}
}
// Player.EventListener 事件回調(diào)方法
@Override
public void onPlayerError(ExoPlaybackException error) {
if (playerStateListener != null) {
playerStateListener.onError(error);
}
}
}這個示例封裝了ExoPlayer的初始化、播放、暫停、停止和釋放等操作,可以在應(yīng)用程序中方便地調(diào)用。使用時,只需要創(chuàng)建一個AudioPlayer對象,然后調(diào)用相應(yīng)的方法即可。還有以下幾個功能:
- 增加了播放器狀態(tài)回調(diào)接口,方便使用者進行狀態(tài)變化的處理和UI更新。
- 增加了獲取當(dāng)前播放進度和媒體源Uri的方法,方便使用者進行狀態(tài)顯示和媒體源管理。
- 實現(xiàn)了ExoPlayer的Player.EventListener回調(diào)接口,方便使用者進行錯誤處理和調(diào)試。
這個封裝示例可能仍然不是完美的,但是對于大多數(shù)應(yīng)用程序的使用場景已經(jīng)足夠成熟。如果需要更加復(fù)雜的功能,可以根據(jù)實際需。
在使用這個封裝類的時候,你需要按以下步驟進行:
在你的Activity或Fragment中創(chuàng)建一個AudioPlayer實例,例如:
private AudioPlayer audioPlayer;
2.在創(chuàng)建完AudioPlayer實例后,調(diào)用init方法初始化。
audioPlayer = new AudioPlayer();
audioPlayer.init(this, Uri.parse("https://example.com/audio.mp3"));其中,第一個參數(shù)傳入當(dāng)前的Context,第二個參數(shù)傳入媒體源的Uri。
3.在需要播放的時候,調(diào)用play方法:
audioPlayer.play();
4.如果需要暫停播放,調(diào)用pause方法:
audioPlayer.pause();
5.如果需要停止播放,調(diào)用stop方法:
audioPlayer.stop();
6.如果需要釋放播放器實例,取消實例化,調(diào)用release方法:
audioPlayer.release();
7.如果需要監(jiān)聽播放器狀態(tài)回調(diào),可以通過setPlayerStateListener方法來設(shè)置:
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.如果需要獲取當(dāng)前播放進度和媒體源Uri,可以調(diào)用getCurrentPosition和getCurrentUri方法:
Uri uri = audioPlayer.getCurrentUri(); audioPlayer.getCurrentPosition();
以上就是大致的調(diào)用步驟,具體情況可以根據(jù)自己的場景進行調(diào)整。
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是用來監(jiān)聽進度的,OnErrorListener是用來監(jiān)聽播放異常的。在init方法中,我們給player對象添加了Player.EventListener接口和AnalyticsListener接口,分別用來監(jiān)聽播放狀態(tài)的變化和進度的變化。播放異常包括播放開始前的異常和播放過程中的異常。在onPlaybackError方法中,我們回調(diào)OnErrorListener接口的onError方法。注意,在捕獲到播放異常時,我們要調(diào)用release方法釋放資源。
最后,通過調(diào)用addOnErrorListener和addOnProgressListener方法,我們可以將外部傳進來的OnErrorListener和OnProgressListener實例添加到AudioPlayer類中。這樣,在播放過程中,我們就可以監(jiān)聽到錯誤和進度的變化了。
至此,我們已經(jīng)完整地實現(xiàn)了一個支持播放暫停、恢復(fù)、停止、進度和錯誤監(jiān)聽的AudioPlayer類。
到此這篇關(guān)于Android Vitamio和ExoPlayer兩種播放器優(yōu)劣分析的文章就介紹到這了,更多相關(guān)Android Vitamio和ExoPlayer內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解Android的Splash啟動圖的兩種動態(tài)切換方式
本篇文章主要介紹了詳解Android的Splash啟動圖的兩種動態(tài)切換方式,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-06-06
Android使用MediaCodec將攝像頭采集的視頻編碼為h264
這篇文章主要為大家詳細介紹了Android使用MediaCodec將攝像頭采集的視頻編碼為h264,具有一定的參考價值,感興趣的小伙伴們可以參考一下2019-10-10
android當(dāng)前apn的狀態(tài)以及獲取方法
在絕大多數(shù)android機器etc路徑下存放一個的apns-conf.xml文件,表示當(dāng)前機器使用的apn信息通過root機器可以push出來看看,具體路徑可以上網(wǎng)搜下,接下來介紹獲取apn的狀態(tài)的方法2013-01-01
Android ViewPager循環(huán)播放廣告實例詳解
這篇文章主要介紹了Android ViewPager循環(huán)播放廣告條實例詳解的相關(guān)資料,需要的朋友可以參考下2017-03-03
android使用RxJava實現(xiàn)預(yù)加載
這篇文章主要為大家詳細介紹了android使用RxJava實現(xiàn)預(yù)加載的相關(guān)資料,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-01-01

