列表支持前后视频预加载
This commit is contained in:
parent
45b63e870e
commit
da258f69f6
|
|
@ -241,9 +241,10 @@ class HomeFragment : AppViewsFragment<ViewBinding, UiState, ViewModel>(), OnSwit
|
|||
handleEventOneVideoSwiped()
|
||||
}
|
||||
|
||||
// Preload next N videos
|
||||
// Preload next N videos and keep previous N videos
|
||||
val preloadCount = 3
|
||||
for (i in 1..preloadCount) {
|
||||
// Next N
|
||||
val nextPos = position + i
|
||||
if (nextPos < mViewPagerAdapter.itemCount) {
|
||||
val nextFragment = mViewPagerAdapter.getFragmentByIndex(nextPos)
|
||||
|
|
@ -251,22 +252,35 @@ class HomeFragment : AppViewsFragment<ViewBinding, UiState, ViewModel>(), OnSwit
|
|||
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) {
|
||||
// Prev N (Keep them ready for playback)
|
||||
val prevPos = position - i
|
||||
if (prevPos >= 0) {
|
||||
val prevFragment = mViewPagerAdapter.getFragmentByIndex(prevPos)
|
||||
if (prevFragment != null && prevFragment is HomeItemFragment) {
|
||||
prevFragment.releasePlayer()
|
||||
prevFragment.preloadVideo()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Release players outside of the window (position - preloadCount - 1)
|
||||
val releasePosBefore = position - preloadCount - 1
|
||||
if (releasePosBefore >= 0) {
|
||||
val prevFragment = mViewPagerAdapter.getFragmentByIndex(releasePosBefore)
|
||||
if (prevFragment != null && prevFragment is HomeItemFragment) {
|
||||
prevFragment.releasePlayer()
|
||||
}
|
||||
}
|
||||
|
||||
// Release players outside of the window (position + preloadCount + 1)
|
||||
val releasePosAfter = position + preloadCount + 1
|
||||
if (releasePosAfter < mViewPagerAdapter.itemCount) {
|
||||
val nextFragment = mViewPagerAdapter.getFragmentByIndex(releasePosAfter)
|
||||
if (nextFragment != null && nextFragment is HomeItemFragment) {
|
||||
nextFragment.releasePlayer()
|
||||
}
|
||||
}
|
||||
|
||||
// load more
|
||||
if (mViewPagerAdapter.itemCount > 0 && position >= mViewPagerAdapter.itemCount - 3) {
|
||||
lifecycleScope.launch {
|
||||
|
|
|
|||
|
|
@ -93,17 +93,23 @@ class HomeItemFragment : AppViewsEmptyViewModelFragment<ViewBinding>() {
|
|||
|
||||
}
|
||||
|
||||
override fun onSaveInstanceState(outState: Bundle) {
|
||||
super.onSaveInstanceState(outState)
|
||||
outState.putFloat("curPlayedSecond", mCurPlayedSecond)
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
if (savedInstanceState != null) {
|
||||
mCurPlayedSecond = savedInstanceState.getFloat("curPlayedSecond", 0f)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
mMaskBitmap?.recycle()
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
fun playVideo() {
|
||||
mIsPreloading = false
|
||||
binding?.playerContainer?.isVisible = true
|
||||
|
|
@ -174,19 +180,21 @@ class HomeItemFragment : AppViewsEmptyViewModelFragment<ViewBinding>() {
|
|||
mPlayerView?.enableAutomaticInitialization = true
|
||||
}
|
||||
|
||||
// val playerUiController = MyPlayerControlView(mPlayerView!!)
|
||||
// mPlayerView!!.setCustomPlayerUi(playerUiController.rootView)
|
||||
mPlayerView!!.removeViews(1, mPlayerView!!.childCount - 1)
|
||||
|
||||
mPlayerView!!.addYouTubePlayerListener(object : AbstractYouTubePlayerListener() {
|
||||
override fun onReady(@NonNull youTubePlayer: YouTubePlayer) {
|
||||
override fun onReady(youTubePlayer: YouTubePlayer) {
|
||||
mPlayer = youTubePlayer
|
||||
val playerUiController = MyPlayerControlView(mPlayerView!!, youTubePlayer)
|
||||
mPlayerView!!.setCustomPlayerUi(playerUiController.rootView)
|
||||
|
||||
if (mPendingPlay) {
|
||||
mPlayer?.loadVideo(mVideoData!!.id, 0f)
|
||||
mPlayer?.loadVideo(mVideoData!!.id, mCurPlayedSecond)
|
||||
} else if (mIsPreloading) {
|
||||
mPlayer?.mute()
|
||||
mPlayer?.loadVideo(mVideoData!!.id, 0f)
|
||||
mPlayer?.loadVideo(mVideoData!!.id, mCurPlayedSecond)
|
||||
} else {
|
||||
mPlayer?.cueVideo(mVideoData!!.id, 0f)
|
||||
mPlayer?.cueVideo(mVideoData!!.id, mCurPlayedSecond)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -232,6 +240,7 @@ class HomeItemFragment : AppViewsEmptyViewModelFragment<ViewBinding>() {
|
|||
PlayerConstants.PlayerState.ENDED -> {
|
||||
togglePlayingState(false)
|
||||
if (!mIsPreloading) {
|
||||
mCurPlayedSecond = 0f
|
||||
mPlayer?.loadVideo(mVideoData!!.id, 0f)
|
||||
}
|
||||
}
|
||||
|
|
@ -272,9 +281,9 @@ class HomeItemFragment : AppViewsEmptyViewModelFragment<ViewBinding>() {
|
|||
private fun togglePlayingState1(isPlaying: Boolean) {
|
||||
if (mIsPlaying != isPlaying) {
|
||||
mIsPlaying = isPlaying
|
||||
if (mIsPlaying) {
|
||||
binding?.circlePb?.isVisible = false
|
||||
}
|
||||
// if (mIsPlaying) {
|
||||
// binding?.circlePb?.isVisible = false
|
||||
// }
|
||||
|
||||
binding?.ivMask?.isVisible = !mIsPlaying
|
||||
// Ensure playerContainer is visible when playing OR preloading (masked)
|
||||
|
|
@ -295,7 +304,7 @@ class HomeItemFragment : AppViewsEmptyViewModelFragment<ViewBinding>() {
|
|||
private fun switchState2Play() {
|
||||
mThumbHandler.removeCallbacksAndMessages(null)
|
||||
|
||||
binding?.circlePb?.isVisible = false
|
||||
// binding?.circlePb?.isVisible = false
|
||||
binding?.ivMask?.isVisible = false
|
||||
binding?.playerContainer?.isVisible = true
|
||||
hidePlayIconAnim()
|
||||
|
|
@ -305,7 +314,7 @@ class HomeItemFragment : AppViewsEmptyViewModelFragment<ViewBinding>() {
|
|||
private fun switchState2Pause() {
|
||||
binding?.ivMask?.isVisible = true
|
||||
binding?.playerContainer?.isVisible = false
|
||||
showPlayIconAnim()
|
||||
// showPlayIconAnim()
|
||||
mTickerTimer.pause()
|
||||
}
|
||||
|
||||
|
|
@ -369,6 +378,7 @@ class HomeItemFragment : AppViewsEmptyViewModelFragment<ViewBinding>() {
|
|||
|
||||
|
||||
private fun hidePlayIconAnim() {
|
||||
return
|
||||
if (!binding?.playIcon!!.isVisible) {
|
||||
return
|
||||
}
|
||||
|
|
@ -404,6 +414,7 @@ class HomeItemFragment : AppViewsEmptyViewModelFragment<ViewBinding>() {
|
|||
}
|
||||
|
||||
private fun showPlayIconAnim() {
|
||||
return
|
||||
with (binding?.playIcon!!) {
|
||||
visibility = View.VISIBLE
|
||||
|
||||
|
|
|
|||
|
|
@ -21,13 +21,14 @@ import com.pierfrancescosoffritti.androidyoutubeplayer.core.customui.menu.YouTub
|
|||
import com.pierfrancescosoffritti.androidyoutubeplayer.core.customui.utils.FadeViewHelper
|
||||
import com.pierfrancescosoffritti.androidyoutubeplayer.core.customui.views.YouTubePlayerSeekBar
|
||||
import com.pierfrancescosoffritti.androidyoutubeplayer.core.customui.views.YouTubePlayerSeekBarListener
|
||||
import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.listeners.YouTubePlayerCallback
|
||||
import kotlin.jvm.javaClass
|
||||
|
||||
|
||||
class MyPlayerControlView(
|
||||
private val youTubePlayerView: YouTubePlayerView,
|
||||
private val youTubePlayer: YouTubePlayer
|
||||
) : PlayerUiController {
|
||||
var youTubePlayer: YouTubePlayer? = null
|
||||
|
||||
val rootView: View = View.inflate(youTubePlayerView.context, R.layout.layout_player_controller, null)
|
||||
|
||||
|
|
@ -133,16 +134,25 @@ class MyPlayerControlView(
|
|||
|
||||
onMenuButtonClickListener = View.OnClickListener { youTubePlayerMenu.show(menuButton) }
|
||||
|
||||
initClickListeners()
|
||||
youTubePlayerView.getYouTubePlayerWhenReady(object : YouTubePlayerCallback{
|
||||
override fun onYouTubePlayer(youTubePlayer: YouTubePlayer) {
|
||||
this@MyPlayerControlView.youTubePlayer = youTubePlayer
|
||||
initClickListeners()
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
private fun initClickListeners() {
|
||||
youTubePlayer.addListener(youtubePlayerSeekBar)
|
||||
youTubePlayer.addListener(fadeControlsContainer)
|
||||
youTubePlayer.addListener(youTubePlayerStateListener)
|
||||
|
||||
youtubePlayerSeekBar.youtubePlayerSeekBarListener = object : YouTubePlayerSeekBarListener {
|
||||
override fun seekTo(time: Float) = youTubePlayer.seekTo(time)
|
||||
private fun initClickListeners() {
|
||||
youTubePlayer?.addListener(youtubePlayerSeekBar)
|
||||
youTubePlayer?.addListener(fadeControlsContainer)
|
||||
youTubePlayer?.addListener(youTubePlayerStateListener)
|
||||
|
||||
youTubePlayer?.let {
|
||||
youtubePlayerSeekBar.youtubePlayerSeekBarListener = object : YouTubePlayerSeekBarListener {
|
||||
override fun seekTo(time: Float) = it.seekTo(time)
|
||||
}
|
||||
}
|
||||
panel.setOnClickListener { fadeControlsContainer.toggleVisibility() }
|
||||
playPauseButton.setOnClickListener { onPlayButtonPressed() }
|
||||
|
|
@ -270,9 +280,9 @@ class MyPlayerControlView(
|
|||
|
||||
private fun onPlayButtonPressed() {
|
||||
if (isPlaying)
|
||||
youTubePlayer.pause()
|
||||
youTubePlayer?.pause()
|
||||
else
|
||||
youTubePlayer.play()
|
||||
youTubePlayer?.play()
|
||||
}
|
||||
|
||||
private fun updateState(state: PlayerConstants.PlayerState) {
|
||||
|
|
|
|||
|
|
@ -8,44 +8,43 @@
|
|||
android:id="@+id/player_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center"/>
|
||||
android:layout_gravity="center" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/iv_mask"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center"
|
||||
android:background="#00000000"
|
||||
android:clickable="false"
|
||||
android:layout_gravity="center"/>
|
||||
android:clickable="false" />
|
||||
|
||||
<View
|
||||
android:id="@+id/click_mask_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:clickable="true"
|
||||
android:layout_marginBottom="30dp"
|
||||
/>
|
||||
android:clickable="true" />
|
||||
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/play_icon"
|
||||
android:layout_width="100dp"
|
||||
android:layout_height="100dp"
|
||||
android:layout_gravity="center"
|
||||
android:padding="20dp"
|
||||
android:src="@mipmap/icon_play"
|
||||
android:visibility="gone"
|
||||
android:layout_gravity="center"/>
|
||||
android:visibility="gone" />
|
||||
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/bottom_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:layout_gravity="bottom"
|
||||
android:layout_marginVertical="25dp"
|
||||
android:layout_marginLeft="15dp"
|
||||
android:layout_marginRight="80dp"
|
||||
android:layout_gravity="bottom">
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_video_from"
|
||||
|
|
@ -53,34 +52,34 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:singleLine="true"
|
||||
android:text="From"
|
||||
android:textSize="15sp"
|
||||
android:textColor="@color/white" />
|
||||
android:textColor="@color/white"
|
||||
android:textSize="15sp" />
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_video_intro"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="5dp"
|
||||
android:text="introduce"
|
||||
android:layout_marginEnd="45dp"
|
||||
android:clickable="false"
|
||||
android:maxLines="2"
|
||||
android:layout_marginEnd="45dp"
|
||||
android:textSize="15sp"
|
||||
android:textColor="@color/white_al80" />
|
||||
android:text="introduce"
|
||||
android:textColor="@color/white_al80"
|
||||
android:textSize="15sp" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/iv_intro_expand"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:layout_gravity="right|bottom"
|
||||
android:paddingHorizontal="10dp"
|
||||
android:paddingVertical="5dp"
|
||||
android:layout_gravity="right|bottom"
|
||||
android:src="@mipmap/arrow_up"
|
||||
android:visibility="gone"
|
||||
/>
|
||||
android:visibility="gone" />
|
||||
</FrameLayout>
|
||||
</LinearLayout>
|
||||
|
||||
|
|
@ -89,18 +88,17 @@
|
|||
android:id="@+id/progress_bar_player"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="3dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:layout_marginHorizontal="15dp"
|
||||
android:layout_gravity="bottom"
|
||||
/>
|
||||
android:layout_marginHorizontal="15dp"
|
||||
android:layout_marginBottom="16dp" />
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/circle_pb"
|
||||
style="?android:attr/progressBarStyleLarge"
|
||||
android:layout_width="35dp"
|
||||
android:layout_height="35dp"
|
||||
android:layout_gravity="center"
|
||||
android:indeterminateTint="@android:color/white"
|
||||
style="?android:attr/progressBarStyleLarge"
|
||||
/>
|
||||
android:visibility="gone" />
|
||||
|
||||
</FrameLayout>
|
||||
Loading…
Reference in New Issue