当recyclerview向上滚动和向下滚动时,youtube视频播放器正在加载已经加载的播放器视频android kotlin为什么会发生这种情况

问题描述 投票:0回答:1
class MediaAdapter(
    private val mediaList: List<VideoItem>,
    private val activity: FragmentActivity // Use FragmentActivity context for lifecycle support
) : RecyclerView.Adapter<MediaAdapter.MediaViewHolder>() {

    class MediaViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        val thumbnail: ImageView = itemView.findViewById(R.id.mediaThumbnail)
        val title: TextView = itemView.findViewById(R.id.mediaTitle)
        val description: TextView = itemView.findViewById(R.id.mediaDescription)
        val webView: WebView = itemView.findViewById(R.id.webView)
        val btnWebFullScreen: ImageView = itemView.findViewById(R.id.fullscreenIcon)
        val playIcon: ImageView = itemView.findViewById(R.id.playIcon)
        var youtubePlayerView: YouTubePlayerView = itemView.findViewById(R.id.youtube_player_view)
        val progressBar: ProgressBar = itemView.findViewById(R.id.progressBar)
        var youtubePlayerDuration:Float = 0.0F


        init {
            // Register FullscreenListener

            youtubePlayerView.addFullscreenListener(object : FullscreenListener {
                override fun onEnterFullscreen(fullscreenView: View, exitFullscreen: () -> Unit) {
                    // Handle entering fullscreen
                    println("full screen listener")

                    // Extract the video ID or URL to pass it to the full-screen activity
                    val videoId = youtubePlayerView.tag as? String

                    println("video Id url... $videoId")
                    if (videoId != null) {
                        println("duration id seconds $youtubePlayerDuration")
                        val tracker = YouTubePlayerTracker()
                        youtubePlayerView.addYouTubePlayerListener(tracker)
                        tracker.state
                        tracker.currentSecond
                        tracker.videoDuration
                        tracker.videoId
                        println("duration value  ${tracker.currentSecond}")
                        println("current State ${tracker.state}")
                        println("current videoId ${tracker.videoId}")
                        val intent = Intent(itemView.context, FullScreenYoutubeViewActivity::class.java).apply {
                            putExtra("VIDEO_SOURCE", "YOUTUBE")
                            putExtra("VIDEO_ID_OR_URL", videoId)
                            putExtra("VIDEO_SEC",youtubePlayerDuration)
                        }
                        itemView.context.startActivity(intent)
                    } else {
                        Toast.makeText(itemView.context, "Unable to enter fullscreen mode", Toast.LENGTH_SHORT).show()
                    }
                }

                override fun onExitFullscreen() {
                    // Handle exiting fullscreen
                }
            })
        }
    }


    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MediaViewHolder {
        val view = LayoutInflater.from(parent.context).inflate(R.layout.row_item_media, parent, false)
        return MediaViewHolder(view)
    }

    override fun onBindViewHolder(holder: MediaViewHolder, position: Int) {
        val videoItem = mediaList[position]
        holder.webView.settings.cacheMode = WebSettings.LOAD_CACHE_ELSE_NETWORK
        holder.webView.visibility = View.GONE
        holder.youtubePlayerView.visibility = View.GONE
        holder.thumbnail.visibility = View.VISIBLE

        // Load the thumbnail image (e.g., using Glide)
        Glide.with(activity)
            .load(videoItem.thumbnail)
            .into(holder.thumbnail)

        holder.title.text = videoItem.title
        holder.description.text = videoItem.description
        holder.webView.setBackgroundColor(Color.TRANSPARENT)

        // Determine if the URL is an embedded video or direct MP4 link
        val isEmbeddedVideo = videoItem.videoUrl.contains("www.youtube.com")
        if (!isEmbeddedVideo) {
            loadWebViewVideo(holder, videoItem)
        } else {
            loadYouTubeVideo(holder, videoItem.videoUrl)
        }
    }

    private fun loadWebViewVideo(holder: MediaViewHolder, videoItem: VideoItem) {
        WebView.setWebContentsDebuggingEnabled(BuildConfig.DEBUG)
        holder.progressBar.visibility = View.VISIBLE  // Show the loader
        holder.thumbnail.visibility = View.VISIBLE
        holder.webView.visibility = View.VISIBLE
        holder.webView.settings.javaScriptEnabled = true
        holder.webView.settings.mediaPlaybackRequiresUserGesture = false
        holder.webView.settings.cacheMode = WebSettings.LOAD_DEFAULT

        // Check if the WebView is already displaying the correct content
        if (holder.webView.url != videoItem.videoUrl) {
            holder.webView.loadUrl(videoItem.videoUrl)
        }


        holder.webView.webViewClient = object : WebViewClient() {
            override fun onPageFinished(view: WebView, url: String) {
                holder.progressBar.visibility = View.GONE
                holder.thumbnail.visibility = View.GONE
//                holder.webView.visibility = View.VISIBLE
            }
        }

        holder.webView.webChromeClient = object : WebChromeClient() {
            override fun onShowCustomView(view: View?, callback: CustomViewCallback?) {
                if (view is FrameLayout) {
                    enterFullscreenMode(view, callback, videoItem.videoUrl)
                }
            }

            override fun onHideCustomView() {
                exitFullscreenMode()
            }
        }

        holder.btnWebFullScreen.setOnClickListener {
            holder.webView.evaluateJavascript("(function(){return document.querySelector('video').currentTime;})()") { result ->
                val currentPosition = result.toDoubleOrNull() ?: 0.0
                val intent = Intent(activity, FullscreenVideoActivity::class.java).apply {
                    putExtra("videoUrl", videoItem.videoUrl)
                    putExtra("playbackPosition", currentPosition)
                }
                activity.startActivity(intent)
            }
        }
    }
    

    // new video play play only clicking the button
    private fun loadYouTubeVideo(holder: MediaViewHolder, videoUrlItem: String) {
        holder.progressBar.visibility = View.VISIBLE
        try {
            val videoId = extractVideoId(videoUrlItem)
            holder.youtubePlayerView.enableAutomaticInitialization = false
            if (videoId != null) {
                val youtubePlayerListener = object : AbstractYouTubePlayerListener() {
                    override fun onReady(youTubePlayer: YouTubePlayer) {
                        if (holder.youtubePlayerView.tag != videoId) {
                            holder.progressBar.visibility = View.GONE  // Hide the loader
                            holder.youtubePlayerView.tag = videoId
                            holder.thumbnail.visibility = View.VISIBLE
                            holder.youtubePlayerView.visibility = View.GONE
                            holder.webView.visibility = View.GONE

                            // Set up play button click listener
                            holder.playIcon.visibility = View.VISIBLE
                            holder.playIcon.setOnClickListener {
                                holder.thumbnail.visibility = View.GONE
                                holder.playIcon.visibility = View.GONE
                                holder.youtubePlayerView.visibility = View.VISIBLE
                                youTubePlayer.cueVideo(videoId, 0f) // Cue the video at 0 seconds
                            }
                        }
                    }
                }

                val iFramePlayerOptions = IFramePlayerOptions.Builder()
                    .controls(1)
                    .fullscreen(1)
                    .build()

                holder.youtubePlayerView.initialize(youtubePlayerListener, iFramePlayerOptions)
            } else {
                Toast.makeText(activity, "Invalid YouTube URL", Toast.LENGTH_SHORT).show()
            }
        } catch (e: Exception) {
            println("Exception: $e")
        }
    }

    private fun extractVideoId(url: String): String? {
        return when {
            url.contains("youtube.com/watch") -> {
                val pattern = Regex("v=([^&]+)")
                pattern.find(url)?.groupValues?.get(1)
            }
            url.contains("youtu.be/") -> {
                val pattern = Regex("youtu\\.be/([^?&]+)")
                pattern.find(url)?.groupValues?.get(1)
            }
            url.contains("youtube.com/embed/") -> {
                val pattern = Regex("embed/([^?&]+)")
                pattern.find(url)?.groupValues?.get(1)
            }
            else -> null
        }
    }

    override fun getItemCount(): Int {
        return mediaList.size
    }

    private fun enterFullscreenMode(
        view: View?,
        callback: WebChromeClient.CustomViewCallback?,
        videoUrl: String
    ) {
        val intent = Intent(activity, FullscreenVideoActivity::class.java).apply {
            putExtra("videoUrl", videoUrl)
        }
        activity.startActivity(intent)
    }

    private fun exitFullscreenMode() {
        println("exit full screen")
    }

}

在此代码中,我的 YouTube 播放器视频加载第一次正确播放,但是当我向下滚动并再次向上滚动时,列表中第一个播放的视频仍在加载,并且需要更多时间加载,有时它不播放视频 YouTube 播放器中的问题是什么视频实现请查看代码 这里我使用这个库来实现 实现(“com.pierfrancescosoffritti.androidyoutubeplayer:核心:12.1.0”)

android kotlin android-recyclerview android-lifecycle youtubeplayer
1个回答
0
投票
  1. RecyclerView 适配器中的 YouTube 播放器初始化 确保在绑定视图时 YouTubePlayerView 已正确初始化。

    类 YoutubeVideoAdapter(private val videoList: List) : RecyclerView.Adapter() {

     inner class YoutubeViewHolder(val binding: ItemYoutubeBinding) : RecyclerView.ViewHolder(binding.root), LifecycleObserver {
    
         fun bind(videoId: String) {
             val youTubePlayerView = binding.youtubePlayerView
             lifecycle.addObserver(youTubePlayerView) // Add lifecycle observer to handle properly
    
             youTubePlayerView.addYouTubePlayerListener(object : AbstractYouTubePlayerListener() {
                 override fun onReady(youTubePlayer: YouTubePlayer) {
                     youTubePlayer.cueVideo(videoId, 0f)
                 }
             })
         }
    
         fun releasePlayer() {
             binding.youtubePlayerView.release()
         }
     }
    
     override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): YoutubeViewHolder {
         val binding = ItemYoutubeBinding.inflate(LayoutInflater.from(parent.context), parent, false)
         return YoutubeViewHolder(binding)
     }
    
     override fun onBindViewHolder(holder: YoutubeViewHolder, position: Int) {
         holder.bind(videoList[position])
     }
    
     override fun onViewRecycled(holder: YoutubeViewHolder) {
         super.onViewRecycled(holder)
         holder.releasePlayer()  // Release player when the view is recycled
     }
    
     override fun getItemCount() = videoList.size
    

    }

  2. 使用生命周期感知的 YouTubePlayerView 确保您的 YouTubePlayerView 具有生命周期感知能力,可以顺利处理初始化、释放和播放。

在您的 Activity 或 Fragment 中:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    val recyclerView = findViewById<RecyclerView>(R.id.recyclerView)
    recyclerView.adapter = YoutubeVideoAdapter(videoList)

    lifecycle.addObserver(object : LifecycleObserver {
        @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
        fun onPause() {
            recyclerView.children.forEach { child ->
                val playerView = child.findViewById<YouTubePlayerView>(R.id.youtubePlayerView)
                playerView?.release()  // Release player when the fragment/activity is paused
            }
        }
    })
}
  1. 为RecyclerView滚动添加生命周期回调 当视图滚动进出视口时,根据需要释放并初始化播放器:
recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
    override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
        if (newState == RecyclerView.SCROLL_STATE_IDLE) {
            // Load the video when scrolling stops
            recyclerView.children.forEach { child ->
                val playerView = child.findViewById<YouTubePlayerView>(R.id.youtubePlayerView)
                if (playerView != null && !playerView.isInitialized) {
                    playerView.getYouTubePlayerWhenReady { player ->
                        // Initialize YouTube player if necessary
                    }
                }
            }
        } else {
            // Pause or release videos when scrolling to avoid lag
            recyclerView.children.forEach { child ->
                val playerView = child.findViewById<YouTubePlayerView>(R.id.youtubePlayerView)
                playerView?.release()
            }
        }
    }
})
  1. 启用硬件加速 确保您的应用程序中启用了硬件加速:

在 AndroidManifest.xml 中:

xml

<application
    android:hardwareAccelerated="true"
    ... >
</application>
© www.soinside.com 2019 - 2024. All rights reserved.