需求: 實現(xiàn)視頻列表的自動播放,無需用戶操作肉微。
在使用Texture遇到一個問題匾鸥。在RK3288 盒子上,直接AndroidStudio 運行app 播放正常浪册,退出到桌面再次打開還是正常播放扫腺。。但是當(dāng)我打包之后村象,安裝apk運行笆环,重復(fù)之前的操作就會頻繁出現(xiàn)有聲音沒有畫面的bug攒至。。躁劣。
猜想: 就是姿勢不對唄迫吐,反正就是一頓瞎搗鼓。
kotlin 代碼如下账忘,有些無用代碼就懶得刪除了志膀。
播放幫助類
class MyPlayerHelper {
companion object {
const val TAG = "MyPlayerHelper"
val shared: MyPlayerHelper by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {
MyPlayerHelper()
}
}
enum class PlayStatus {
stop,
playing,
paused
}
private var mediaPlayer: MediaPlayer? = null
private var curStatus: PlayStatus = PlayStatus.stop
private var ltVideoWrapper: LinearLayout? = null
private var lastPosition: Int = 0
private var mSurface: Surface? = null
private var videoList: ArrayList<Video> = ArrayList()
private var videoIdx = 0
private fun videoListChanged(list: List<Video>) : Boolean {
if (list.size != videoList.size) return true
if (videoList.containsAll(list) && list.containsAll(videoList)) {
return false
}
return true
}
/**
* 初始化 播放器
*/
private fun initPlayer() {
AppHelper.logD(TAG, "lxf video initPlayer")
if (mediaPlayer == null) {
mediaPlayer = MediaPlayer()
mediaPlayer!!.setScreenOnWhilePlaying(true)
mediaPlayer!!.setOnCompletionListener(object : MediaPlayer.OnCompletionListener {
override fun onCompletion(mp: MediaPlayer?) {
//播放完成
if (videoList.size > 1) {
playNext()
} else {
mp?.isLooping = true
}
}
})
mediaPlayer?.setOnErrorListener(object : MediaPlayer.OnErrorListener {
override fun onError(mp: MediaPlayer?, p1: Int, p2: Int): Boolean {
return false
}
})
mediaPlayer?.setOnInfoListener(object : MediaPlayer.OnInfoListener {
override fun onInfo(mp: MediaPlayer?, p1: Int, p2: Int): Boolean {
return false
}
})
mediaPlayer?.setOnPreparedListener(object : MediaPlayer.OnPreparedListener {
override fun onPrepared(mp: MediaPlayer?) {
// mp?.seekTo(lastPosition)
mp?.start()
}
})
mediaPlayer?.setOnSeekCompleteListener(object : MediaPlayer.OnSeekCompleteListener {
override fun onSeekComplete(mp: MediaPlayer?) {
// AppHelper.logD(TAG, "lxf video onSeekComplete")
// mp?.start()
}
})
mediaPlayer?.setOnVideoSizeChangedListener(object :
MediaPlayer.OnVideoSizeChangedListener {
override fun onVideoSizeChanged(mp: MediaPlayer?, p1: Int, p2: Int) {
// videoFitCenter()
}
})
}
}
/**
* 播放下一個
*/
private fun playNext() {
AppHelper.logD(TAG, "lxf video playNext")
videoIdx += 1
play()
}
/**
* 播放
*/
private fun play() {
AppHelper.logD(TAG, "lxf video play")
try {
if (videoList.size == 0){
return
}
if (videoIdx >= videoList.size) {
videoIdx = 0
lastPosition = 0
}
initPlayer()
val content = videoList[videoIdx]
//網(wǎng)絡(luò)播放
val url: String = content.videoUrl
val fileName = content.getVideoName()
val filePath = AppHelper.shared.getFileDownloadPath() + fileName
val file = File(filePath)
mediaPlayer?.let {
it.reset()
it.setSurface(mSurface)
if (file.exists()) {
it.setDataSource(filePath)
} else {
it.setDataSource(url)
}
it.prepareAsync()
}
} catch (e: Exception) {
e.printStackTrace()
AppHelper.logD(TAG, "lxf video play Exception")
val txt: String = Date().format("yyyy-MM-dd HH:mm:ss \n") + LzApplication.shared().tek.ethMac + AppHelper.shared.currentWharf?.name + "視頻播放異常\n${e.localizedMessage}"
AppHelper.shared.uploadCrashLog(txt)
}
}
/**
* 更新畫面
*/
fun updateSurfaceTexture(surface: SurfaceTexture) {
mSurface = Surface(surface)
// mediaPlayer?.setSurface(mSurface)
}
/**
* 開始播放視頻
*/
fun startPlay(surface: SurfaceTexture) {
mSurface = Surface(surface)
play()
}
/**
* 停止播放
*/
fun isStop() : Boolean {
return curStatus == PlayStatus.stop
}
/**
* 暫停播放
*/
fun isPaused() : Boolean {
return curStatus == PlayStatus.paused
}
/**
* 正在播放
*/
fun isPlaying() : Boolean {
return curStatus == PlayStatus.playing
}
/**
* 開始播放
*/
fun setPlayList(list: List<Video>) {
if (videoListChanged(list)) {
AppHelper.logD(TAG, "lxf video setPlayList")
videoList.clear()
videoList.addAll(list)
//
// ///
// if (curStatus == PlayStatus.stop) {
// videoIdx = 0
// play()
// }
}
}
/**
* 停止播放
*/
fun stopPlay() {
AppHelper.logD(TAG, "lxf video stopPlay")
mSurface = null
mediaPlayer?.stop()
mediaPlayer?.release()
mediaPlayer = null
curStatus = PlayStatus.stop
videoIdx = 0
videoList.clear()
}
/**
* 繼續(xù)播放
*/
fun continuePlay() {
AppHelper.logD(TAG, " continuePlay")
if (curStatus == PlayStatus.paused) {
mediaPlayer?.let {
if (!it.isPlaying) {
it.start()
curStatus = PlayStatus.playing
AppHelper.logD(TAG, " continuePlay 繼續(xù)播放")
}
}
} else if (curStatus == PlayStatus.stop) {
AppHelper.logD(TAG, " continuePlay 從頭播放")
videoIdx = 0
play()
}
}
/**
* 暫停播放
*/
fun pausePlay() {
AppHelper.logD(TAG, "lxf video pausePlay")
mediaPlayer?.let {
if (it.isPlaying && curStatus != PlayStatus.paused) {
it.pause()
lastPosition = it.currentPosition
curStatus = PlayStatus.paused
}
}
}
/**
* 將視頻居中對齊
*/
private fun videoFitCenter() {
ltVideoWrapper?.let {
var vWidth: Int = mediaPlayer?.videoWidth ?: 0
var vHeight: Int = mediaPlayer?.videoHeight ?: 0
val lw: Int = it.width
val lh: Int = it.height
if (vWidth > lw || vHeight > lh) {
val rw = vWidth * 1f / lw
val rh = vHeight * 1f / lh
val r = max(rw, rh)
vWidth = ceil(vWidth * 1f / r).toInt()
vHeight = ceil(vHeight * 1f / r).toInt()
}
val lp: LinearLayout.LayoutParams = LinearLayout.LayoutParams(vWidth, vHeight)
lp.gravity = Gravity.CENTER
// surfaceView?.layoutParams = lp
}
}
}
/***
* 增加監(jiān)聽
*/
private fun addSurfaceTextureListener() {
textureView?.surfaceTextureListener = object : TextureView.SurfaceTextureListener {
override fun onSurfaceTextureAvailable(
surface: SurfaceTexture,
width: Int,
height: Int
) {
AppHelper.logD(MyPlayerHelper.TAG, "onSurfaceTextureAvailable")
MyPlayerHelper.shared.startPlay(surface)
}
override fun onSurfaceTextureSizeChanged(
surface: SurfaceTexture,
width: Int,
height: Int
) {
AppHelper.logD(MyPlayerHelper.TAG, "onSurfaceTextureSizeChanged")
}
override fun onSurfaceTextureDestroyed(surface: SurfaceTexture): Boolean {
AppHelper.logD(MyPlayerHelper.TAG, "onSurfaceTextureDestroyed")
MyPlayerHelper.shared.stopPlay()
return true
}
override fun onSurfaceTextureUpdated(surface: SurfaceTexture) {
// MyPlayerHelper.shared.updateSurfaceTexture(surface)
}
}
}