视频优化
This commit is contained in:
parent
13ee0de952
commit
6f34b5b990
|
|
@ -65,6 +65,8 @@ class ShushuManager private constructor() {
|
|||
config.setMode(/*if (BuildConfig.DEBUG) TDConfig.ModeEnum.DEBUG else*/ TDConfig.ModeEnum.DEBUG)
|
||||
// config.setMode(/*if (BuildConfig.DEBUG) TDConfig.ModeEnum.DEBUG else*/ TDConfig.ModeEnum.NORMAL)
|
||||
mShushuSdk = ThinkingAnalyticsSDK.sharedInstance(config)
|
||||
|
||||
StatisticLogger.d("数数DeviceID: ${TDAnalytics.getDeviceId()}")
|
||||
configAutoTrack()
|
||||
sdkReady = true
|
||||
flushPendingEventsAsync()
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ class HomeFragment : AppViewsFragment<ViewBinding, UiState, ViewModel>(), OnSwit
|
|||
|
||||
override fun ViewBinding.initViews() {
|
||||
viewPager2.setPageTransformer { _, _ -> }
|
||||
viewPager2.offscreenPageLimit = 1
|
||||
viewPager2.offscreenPageLimit = 3
|
||||
viewPager2.adapter = mViewPagerAdapter
|
||||
|
||||
|
||||
|
|
@ -236,13 +236,39 @@ class HomeFragment : AppViewsFragment<ViewBinding, UiState, ViewModel>(), OnSwit
|
|||
if (fragment != null) {
|
||||
setHomeTabStyle(fragment)
|
||||
val curFragment: HomeItemFragment = fragment as HomeItemFragment
|
||||
curFragment.loadVideo()
|
||||
curFragment.playVideo()
|
||||
|
||||
handleEventOneVideoSwiped()
|
||||
}
|
||||
|
||||
// Preload next N videos
|
||||
val preloadCount = 3
|
||||
for (i in 1..preloadCount) {
|
||||
val nextPos = position + i
|
||||
if (nextPos < mViewPagerAdapter.itemCount) {
|
||||
val nextFragment = mViewPagerAdapter.getFragmentByIndex(nextPos)
|
||||
if (nextFragment != null && nextFragment is HomeItemFragment) {
|
||||
nextFragment.preloadVideo()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Release players for previous fragments to save memory
|
||||
// We keep 'preloadCount' fragments after current, and maybe 0 before?
|
||||
// But offscreenPageLimit keeps them in memory. We should release their heavy resources.
|
||||
val offscreenLimit = 3
|
||||
for (i in 1..offscreenLimit) {
|
||||
val prevPos = position - i
|
||||
if (prevPos >= 0) {
|
||||
val prevFragment = mViewPagerAdapter.getFragmentByIndex(prevPos)
|
||||
if (prevFragment != null && prevFragment is HomeItemFragment) {
|
||||
prevFragment.releasePlayer()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// load more
|
||||
if (mViewPagerAdapter.itemCount > 0 && position == mViewPagerAdapter.itemCount - 2) {
|
||||
if (mViewPagerAdapter.itemCount > 0 && position >= mViewPagerAdapter.itemCount - 3) {
|
||||
lifecycleScope.launch {
|
||||
mViewModel.loadVideoList()
|
||||
}
|
||||
|
|
@ -262,7 +288,6 @@ class HomeFragment : AppViewsFragment<ViewBinding, UiState, ViewModel>(), OnSwit
|
|||
}, false)
|
||||
|
||||
|
||||
viewPager2.offscreenPageLimit = 3
|
||||
}
|
||||
|
||||
override fun ViewBinding.initObservers() {
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import androidx.core.view.isVisible
|
|||
import com.ama.core.architecture.appBase.AppViewsEmptyViewModelFragment
|
||||
import com.ama.core.architecture.util.AndroidUtil
|
||||
import com.ama.core.architecture.util.setOnClickBatch
|
||||
import com.blankj.utilcode.util.LogUtils
|
||||
import com.gamedog.statisticreporter.StatisticUtil
|
||||
import com.viddin.videos.free.R
|
||||
import com.gamedog.vididin.beans.YoutubeVideo
|
||||
|
|
@ -27,6 +28,7 @@ import com.gamedog.vididin.youtubestatistic.TickerTimer
|
|||
import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.PlayerConstants
|
||||
import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.YouTubePlayer
|
||||
import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.listeners.AbstractYouTubePlayerListener
|
||||
import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.listeners.YouTubePlayerCallback
|
||||
import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.utils.loadOrCueVideo
|
||||
import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.views.YouTubePlayerView
|
||||
import com.viddin.videos.free.databinding.VididinappFeatureHomeItemLayoutBinding as ViewBinding
|
||||
|
|
@ -43,6 +45,8 @@ class HomeItemFragment : AppViewsEmptyViewModelFragment<ViewBinding>() {
|
|||
private var mCurPlayedSecond: Float = 0F
|
||||
private var mTotalDuration: Float = 0F
|
||||
private val mTickerTimer = TickerTimer()
|
||||
private var mPendingPlay: Boolean = false
|
||||
private var mIsPreloading: Boolean = false
|
||||
|
||||
private val mThumbHandler = Handler(Looper.getMainLooper())
|
||||
|
||||
|
|
@ -100,27 +104,67 @@ class HomeItemFragment : AppViewsEmptyViewModelFragment<ViewBinding>() {
|
|||
|
||||
|
||||
|
||||
private fun playVideo() {
|
||||
if (mPlayer != null && mVideoData != null && !mVideoData?.id.isNullOrEmpty()) {
|
||||
mPlayer?.loadOrCueVideo(
|
||||
lifecycle,
|
||||
mVideoData!!.id,
|
||||
0f
|
||||
)
|
||||
fun playVideo() {
|
||||
mIsPreloading = false
|
||||
binding?.playerContainer?.isVisible = true
|
||||
if (mPlayerView == null) {
|
||||
initPlayerView(true)
|
||||
} else {
|
||||
if (mPlayer != null) {
|
||||
mPlayer?.unMute()
|
||||
mPlayer?.play()
|
||||
} else {
|
||||
mPendingPlay = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*mPlayerView?.isVisible?.let {
|
||||
if (!it) {
|
||||
mPlayer?.pause()
|
||||
fun preloadVideo() {
|
||||
if (mPlayerView == null) {
|
||||
mIsPreloading = true
|
||||
binding?.playerContainer?.isVisible = true
|
||||
initPlayerView(false)
|
||||
} else {
|
||||
if (mPlayer != null && mIsPreloading) {
|
||||
// Already preloading or preloaded
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
fun releasePlayer() {
|
||||
LogUtils.d("[视频Item] releasePlayer ID: ${getVideoId()}")
|
||||
mIsPreloading = false
|
||||
mPendingPlay = false
|
||||
|
||||
if (mPlayerView != null) {
|
||||
// Try to save last frame as mask if possible and not already saved
|
||||
if (mMaskBitmap == null && binding?.playerContainer?.isVisible == true) {
|
||||
// This is a best-effort sync capture or just skip to avoid async complexity during release
|
||||
// For now, we just release to free memory immediately.
|
||||
}
|
||||
|
||||
mPlayerView!!.release()
|
||||
binding?.playerContainer?.removeView(mPlayerView)
|
||||
mPlayerView = null
|
||||
mPlayer = null
|
||||
}
|
||||
|
||||
binding?.playerContainer?.isVisible = false
|
||||
binding?.ivMask?.isVisible = true
|
||||
if (mMaskBitmap != null) {
|
||||
binding?.ivMask?.setImageBitmap(mMaskBitmap)
|
||||
}
|
||||
showPlayIconAnim()
|
||||
mTickerTimer.pause()
|
||||
}
|
||||
|
||||
fun getVideoId(): String? {
|
||||
return mVideoData?.id
|
||||
}
|
||||
|
||||
fun loadVideo() {
|
||||
private fun initPlayerView(autoPlay: Boolean) {
|
||||
mPendingPlay = autoPlay
|
||||
LogUtils.d("[视频Item] initPlayerView ID: ${getVideoId()} autoPlay: $autoPlay")
|
||||
if (null == mPlayerView) {
|
||||
mPlayerView = YouTubePlayerView(requireContext())
|
||||
val layoutParam = FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)
|
||||
|
|
@ -130,16 +174,20 @@ class HomeItemFragment : AppViewsEmptyViewModelFragment<ViewBinding>() {
|
|||
mPlayerView?.enableAutomaticInitialization = true
|
||||
}
|
||||
|
||||
|
||||
val playerView = mPlayerView
|
||||
playerView!!.addYouTubePlayerListener(object : AbstractYouTubePlayerListener() {
|
||||
mPlayerView!!.addYouTubePlayerListener(object : AbstractYouTubePlayerListener() {
|
||||
override fun onReady(@NonNull youTubePlayer: YouTubePlayer) {
|
||||
mPlayer = youTubePlayer
|
||||
val playerUiController = MyPlayerControlView(mPlayerView!!, youTubePlayer)
|
||||
mPlayerView!!.setCustomPlayerUi(playerUiController.rootView)
|
||||
|
||||
val playerUiController = MyPlayerControlView(playerView, youTubePlayer)
|
||||
playerView.setCustomPlayerUi(playerUiController.rootView)
|
||||
|
||||
playVideo()
|
||||
if (mPendingPlay) {
|
||||
mPlayer?.loadVideo(mVideoData!!.id, 0f)
|
||||
} else if (mIsPreloading) {
|
||||
mPlayer?.mute()
|
||||
mPlayer?.loadVideo(mVideoData!!.id, 0f)
|
||||
} else {
|
||||
mPlayer?.cueVideo(mVideoData!!.id, 0f)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCurrentSecond(youTubePlayer: YouTubePlayer, second: Float) {
|
||||
|
|
@ -160,10 +208,20 @@ class HomeItemFragment : AppViewsEmptyViewModelFragment<ViewBinding>() {
|
|||
) {
|
||||
when (state) {
|
||||
PlayerConstants.PlayerState.PLAYING -> {
|
||||
if (mIsPreloading) {
|
||||
mPlayer?.pause()
|
||||
} else {
|
||||
togglePlayingState(true)
|
||||
}
|
||||
}
|
||||
PlayerConstants.PlayerState.PAUSED -> {
|
||||
if (mIsPreloading) {
|
||||
// Do nothing or ensure mask is visible?
|
||||
// togglePlayingState(false) sets mask visible.
|
||||
togglePlayingState(false)
|
||||
} else {
|
||||
togglePlayingState(false)
|
||||
}
|
||||
}
|
||||
PlayerConstants.PlayerState.UNKNOWN -> {
|
||||
togglePlayingState(false)
|
||||
|
|
@ -173,7 +231,9 @@ class HomeItemFragment : AppViewsEmptyViewModelFragment<ViewBinding>() {
|
|||
}
|
||||
PlayerConstants.PlayerState.ENDED -> {
|
||||
togglePlayingState(false)
|
||||
playVideo()
|
||||
if (!mIsPreloading) {
|
||||
mPlayer?.loadVideo(mVideoData!!.id, 0f)
|
||||
}
|
||||
}
|
||||
PlayerConstants.PlayerState.BUFFERING -> {
|
||||
//binding?.circlePb?.isVisible = true
|
||||
|
|
@ -217,7 +277,8 @@ class HomeItemFragment : AppViewsEmptyViewModelFragment<ViewBinding>() {
|
|||
}
|
||||
|
||||
binding?.ivMask?.isVisible = !mIsPlaying
|
||||
binding?.playerContainer?.isVisible = mIsPlaying
|
||||
// Ensure playerContainer is visible when playing OR preloading (masked)
|
||||
binding?.playerContainer?.isVisible = mIsPlaying || mIsPreloading
|
||||
|
||||
if (mIsPlaying) {
|
||||
hidePlayIconAnim()
|
||||
|
|
|
|||
Loading…
Reference in New Issue