需求: 实现视频列表的自动播放,无需用户操作。
在使用Texture遇到一个问题。在RK3288 盒子上,直接AndroidStudio 运行app 播放正常,退出到桌面再次打开还是正常播放。。但是当我打包之后,安装apk运行,重复之前的操作就会频繁出现有声音没有画面的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]
//网络播放
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()
* 继续播放
fun continuePlay() {
AppHelper.logD(TAG, " continuePlay")
if (curStatus == PlayStatus.paused) {
mediaPlayer?.let {
if (!it.isPlaying) {
it.start()
curStatus = PlayStatus.playing
AppHelper.logD(TAG, " continuePlay 继续播放")
} 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
* 增加监听
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)