feat:完善Exoplayer
feat:新增资源下载(Glide版本)未测试验证是否有bug
This commit is contained in:
@@ -0,0 +1,17 @@
|
|||||||
|
package com.chuhai.core.download
|
||||||
|
|
||||||
|
import com.chuhai.core.exceptions.SuperException
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Max on 2022/5/12 21:05
|
||||||
|
* Desc:下载异常
|
||||||
|
**/
|
||||||
|
class DownloadException : SuperException {
|
||||||
|
|
||||||
|
constructor(message: String) : super(message)
|
||||||
|
|
||||||
|
constructor(throwable: Throwable) : super(
|
||||||
|
throwable
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,21 @@
|
|||||||
|
package com.chuhai.core.download
|
||||||
|
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Max on 3/6/21 10:29 AM
|
||||||
|
* Desc:下载监听器
|
||||||
|
*/
|
||||||
|
interface DownloadListener {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 下载完成
|
||||||
|
*/
|
||||||
|
fun onDownloadCompleted(result: File) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 下载异常
|
||||||
|
*/
|
||||||
|
fun onDownloadError(exception: DownloadException) {}
|
||||||
|
}
|
@@ -13,7 +13,7 @@ interface IPlayer : ICleared {
|
|||||||
/**
|
/**
|
||||||
* 绑定页面生命周期
|
* 绑定页面生命周期
|
||||||
*/
|
*/
|
||||||
fun bindingLifeCycle(lifecycleOwner: LifecycleOwner)
|
fun bindLifeCycle(lifecycleOwner: LifecycleOwner)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 加载视频源(加载后根据playWhenReady觉得是否播放)
|
* 加载视频源(加载后根据playWhenReady觉得是否播放)
|
||||||
|
@@ -0,0 +1,60 @@
|
|||||||
|
package com.chuhai.core.player.download
|
||||||
|
|
||||||
|
import android.graphics.drawable.Drawable
|
||||||
|
import com.bumptech.glide.Glide
|
||||||
|
import com.bumptech.glide.request.target.CustomTarget
|
||||||
|
import com.bumptech.glide.request.transition.Transition
|
||||||
|
import com.chuhai.core.download.DownloadException
|
||||||
|
import com.chuhai.core.download.DownloadListener
|
||||||
|
import com.chuhai.utils.AppUtils
|
||||||
|
import com.chuhai.utils.log.ILog
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Max on 2023/11/3 12:11
|
||||||
|
* Desc:Glide 实现下载器功能
|
||||||
|
* PS:没有在项目中找到下载器组件,之前的VAP视频是通过Glide下载的,这里暂且也采用这种方式,后续考虑搞个独立的下载组件!!
|
||||||
|
* TODO ⚠️写好后还未测试验证是否有bug
|
||||||
|
**/
|
||||||
|
class GlideDownload(private val timeout: Int = 15000) : MediaDownloader, ILog {
|
||||||
|
|
||||||
|
private val targetList: ArrayList<CustomTarget<File>> by lazy {
|
||||||
|
ArrayList()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun download(url: String, listener: DownloadListener) {
|
||||||
|
val target = object : CustomTarget<File>() {
|
||||||
|
override fun onResourceReady(resource: File, transition: Transition<in File>?) {
|
||||||
|
targetList.remove(this)
|
||||||
|
listener.onDownloadCompleted(resource)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onLoadFailed(errorDrawable: Drawable?) {
|
||||||
|
super.onLoadFailed(errorDrawable)
|
||||||
|
targetList.remove(this)
|
||||||
|
listener.onDownloadError(DownloadException("下载失败"))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onLoadCleared(placeholder: Drawable?) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Glide.with(AppUtils.getApp())
|
||||||
|
.asFile()
|
||||||
|
.dontTransform()
|
||||||
|
.timeout(timeout)
|
||||||
|
.load(url).into(target)
|
||||||
|
targetList.add(target)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCleared() {
|
||||||
|
super.onCleared()
|
||||||
|
try {
|
||||||
|
targetList.forEach {
|
||||||
|
Glide.with(AppUtils.getApp()).clear(it)
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
targetList.clear()
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,23 @@
|
|||||||
|
package com.chuhai.core.player.download
|
||||||
|
|
||||||
|
import com.chuhai.core.download.DownloadListener
|
||||||
|
import com.chuhai.utils.ICleared
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Max on 2023/11/3 12:45
|
||||||
|
* Desc:媒体资源下载器
|
||||||
|
*/
|
||||||
|
interface MediaDownloader : ICleared {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 下载
|
||||||
|
*/
|
||||||
|
fun download(url: String, listener: DownloadListener)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 释放
|
||||||
|
*/
|
||||||
|
override fun onCleared() {
|
||||||
|
super.onCleared()
|
||||||
|
}
|
||||||
|
}
|
@@ -3,12 +3,15 @@ package com.chuhai.core.player.exo
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import androidx.lifecycle.Lifecycle
|
||||||
|
import androidx.lifecycle.LifecycleEventObserver
|
||||||
import androidx.lifecycle.LifecycleOwner
|
import androidx.lifecycle.LifecycleOwner
|
||||||
import com.chuhai.core.player.IPlayer
|
import com.chuhai.core.player.IPlayer
|
||||||
import com.chuhai.core.player.PlayerListener
|
|
||||||
import com.chuhai.core.player.PlayerMediaItem
|
|
||||||
import com.chuhai.core.player.PlaybackState
|
import com.chuhai.core.player.PlaybackState
|
||||||
import com.chuhai.core.player.PlayerException
|
import com.chuhai.core.player.PlayerException
|
||||||
|
import com.chuhai.core.player.PlayerListener
|
||||||
|
import com.chuhai.core.player.PlayerMediaItem
|
||||||
|
import com.google.android.exoplayer2.DefaultLoadControl
|
||||||
import com.google.android.exoplayer2.MediaItem
|
import com.google.android.exoplayer2.MediaItem
|
||||||
import com.google.android.exoplayer2.PlaybackException
|
import com.google.android.exoplayer2.PlaybackException
|
||||||
import com.google.android.exoplayer2.Player
|
import com.google.android.exoplayer2.Player
|
||||||
@@ -20,7 +23,7 @@ import com.google.android.exoplayer2.ExoPlayer as ExoPlayerImpl
|
|||||||
* Created by Max on 2023/11/2 14:50
|
* Created by Max on 2023/11/2 14:50
|
||||||
* Desc:基于Exo
|
* Desc:基于Exo
|
||||||
**/
|
**/
|
||||||
class ExoPlayer : StyledPlayerView, IPlayer {
|
class ExoPlayer : StyledPlayerView, IPlayer, LifecycleEventObserver {
|
||||||
|
|
||||||
private var currentItem: ExoMediaItem? = null
|
private var currentItem: ExoMediaItem? = null
|
||||||
|
|
||||||
@@ -30,6 +33,9 @@ class ExoPlayer : StyledPlayerView, IPlayer {
|
|||||||
|
|
||||||
private var listenerAdapter: Player.Listener? = null
|
private var listenerAdapter: Player.Listener? = null
|
||||||
|
|
||||||
|
// 操作的记录(用于感知生命周期恢复播放或其他场景的判断)
|
||||||
|
private var playWhenReadyBackup = getPlayWhenReady()
|
||||||
|
|
||||||
constructor(context: Context) : this(context, null)
|
constructor(context: Context) : this(context, null)
|
||||||
constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)
|
constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)
|
||||||
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(
|
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(
|
||||||
@@ -37,11 +43,23 @@ class ExoPlayer : StyledPlayerView, IPlayer {
|
|||||||
attrs,
|
attrs,
|
||||||
defStyleAttr
|
defStyleAttr
|
||||||
) {
|
) {
|
||||||
player = ExoPlayerImpl.Builder(context).build()
|
/**
|
||||||
|
* 缓冲策略:目前先用默认的,后续结合需求场景再调整
|
||||||
|
*/
|
||||||
|
val loadControl = DefaultLoadControl.Builder()
|
||||||
|
.setBufferDurationsMs(
|
||||||
|
DefaultLoadControl.DEFAULT_MIN_BUFFER_MS,
|
||||||
|
DefaultLoadControl.DEFAULT_MAX_BUFFER_MS,
|
||||||
|
DefaultLoadControl.DEFAULT_BUFFER_FOR_PLAYBACK_MS,
|
||||||
|
DefaultLoadControl.DEFAULT_BUFFER_FOR_PLAYBACK_AFTER_REBUFFER_MS
|
||||||
|
).build()
|
||||||
|
player = ExoPlayerImpl.Builder(context).setLoadControl(loadControl).build()
|
||||||
|
useController = false
|
||||||
setPlayer(player)
|
setPlayer(player)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun bindingLifeCycle(lifecycleOwner: LifecycleOwner) {
|
override fun bindLifeCycle(lifecycleOwner: LifecycleOwner) {
|
||||||
|
lifecycleOwner.lifecycle.addObserver(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun prepare(item: PlayerMediaItem) {
|
override fun prepare(item: PlayerMediaItem) {
|
||||||
@@ -60,6 +78,7 @@ class ExoPlayer : StyledPlayerView, IPlayer {
|
|||||||
|
|
||||||
override fun setPlayWhenReady(playWhenReady: Boolean) {
|
override fun setPlayWhenReady(playWhenReady: Boolean) {
|
||||||
this.player.playWhenReady = playWhenReady
|
this.player.playWhenReady = playWhenReady
|
||||||
|
this.playWhenReadyBackup = playWhenReady
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getPlayWhenReady(): Boolean {
|
override fun getPlayWhenReady(): Boolean {
|
||||||
@@ -133,4 +152,21 @@ class ExoPlayer : StyledPlayerView, IPlayer {
|
|||||||
this.currentItem?.onCleared()
|
this.currentItem?.onCleared()
|
||||||
this.currentItem = null
|
this.currentItem = null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
|
||||||
|
// TODO 这个方法的代码 还未进行测试,目前需求貌似用不上,后续需要再验证!
|
||||||
|
when (event) {
|
||||||
|
Lifecycle.Event.ON_RESUME -> {
|
||||||
|
setPlayWhenReady(playWhenReadyBackup)
|
||||||
|
}
|
||||||
|
|
||||||
|
Lifecycle.Event.ON_PAUSE -> {
|
||||||
|
player.playWhenReady = false
|
||||||
|
}
|
||||||
|
|
||||||
|
Lifecycle.Event.ON_DESTROY -> {
|
||||||
|
onCleared()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
Reference in New Issue
Block a user