本文章就kotlin实现的一个视频播放器做一个讲解。
技术栈:MVVM+Kotlin
UI:SurfaceView+Recyclerview
一 .加载流程:
(1)数据获取:
进入主页面->权限获取(动态读写权限)->遍历手机文件夹->获取mp4文件路径集合->返回给到主页面->RecyclerView列表加载
(2)播放流程
点击播放列表(上下曲)->获取当前媒体url->MediaPlayer进行播放
点击播放(暂停)->MediaPlayer设置播放(暂停)
点击循环模式->播放模式字段设置->url根据字段调整
二.代码流程(媒体url集合获取):
数据获取:MainActivity->MainViewModel->MainModel->VideoFileTask
UI展示:VideoTask->MainViewModel->MainActivity->RecyclerView
详细:
MainActivity获取MainViewModel对象
Kotlin
mainViewModel = ViewModelProvider(this).get(MainViewModel::class.java)
MainActivity监听数据回调
Kotlin
mainViewModel.mainData.observe(this, Observer {
refreshData(it)
})
MainActivity主动获取媒体url集合代码流程
Kotlin
//获取权限后,去遍历文件夹获取url集合
override fun hasFilePermission(hasPerssion: Boolean) {
when (hasPerssion) {
true -> mainViewModel.scanFile()
false -> "no permission"
}
}
//MainViewModel层调用MainModel层遍历文件方法
override fun scanFile() {
mainModel.scanFile {
mainModel.initPosition(0, it)//设置播放初始位置,初始化遍历获取的url集合
mainData.postValue(transToCurrentNeedData(it))//url集合返回给到 MainActivity
}
}
//MainModel层方法,单例调用VideoFileTask方法
fun scanFile(onVideoListCallback: (MutableList<String>) -> Unit) {
VideoFileTask.getVideoFileTask()?.findMusicFile(onVideoListCallback)
}
//VideoFileTask层方法,创建协程,遍历文件夹获取url集合
/**
* 查找本地媒体文件
*/
fun findVideoFile(onVideoListCallback: (MutableList<String>) -> Unit) {
val rootUrl: String = Environment.getExternalStorageDirectory().path
val rootFile: File = File(rootUrl)
mainScope.launch(Dispatchers.Main) {
onVideoListCallback(withContext(Dispatchers.IO) {
videos.clear()
loopFile(rootFile)
videos
})
}
}
/**
* 循环遍历文件夹获取文件后缀为.mp4的文件
*/
private fun loopFile(file: File) {
val files = file.listFiles()
if (files != null) {
files.forEach {
if (it.isDirectory) {
loopFile(it)
} else {
if (it.path.contains(".mp4")) {
videos.add(it.path)
}
}
}
}
}
(三)播放控制代码流程(只讲播放逻辑,其他类似)
Kotlin
//MainActivity主页面点击播放列表
private fun listenAdapterClick() {
mediaAdapter.listenMusicClick { url: String, position: Int ->
visibleBottomBarOnce()//ui处理,显示底部栏
mainViewModel.mainModel.play(position)//调用播放指令
}
}
//MainModel层开始播放
fun play(position: Int) {
// musicPlayer.release()
//判断是否点击播放按钮
if (!isInit) return
if (position == POSITON_INIT) {
if (!mediaPlayer.isPlaying) {
if (isPrepared) {
play()
} else {
play(0)
}
}
return
}
var resultUrl = data[position]
if (resultUrl.isEmpty()) {
return
}
if (mediaPlayer.isPlaying && currentPosition == position) {
return
} else {
mediaPlayer.reset()
}
mediaPlayer.setDataSource(resultUrl)
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC)
mediaPlayer.prepareAsync()
playPosition = position
currentPosition = position
onPositionCallback(position)//播放位置更新返回给ui
}
(四)代码结构:

(五)效果

(六)上传地址(gitee)