admin管理员组文章数量:1390571
I want to show videoes in recycler view, the problem is when I swap from the first video and back to the first, the first video reloads again, I want to make all videoes loaded at once and when I swap keep the video loaded. this lines in fragment =>
// Setup StoryBoardAdapter
val storyboardAdapter = StoryBoardAdapter(requireContext(), DataRepository.storyBoardList)
val layoutManager = LinearLayoutManager(requireContext(), LinearLayoutManager.HORIZONTAL, false)
binding.recyclerViewStoryBoard.layoutManager = layoutManager
binding.recyclerViewStoryBoard.adapter = storyboardAdapter
// Attach PagerSnapHelper to show one item at a time
val pagerSnapHelper = PagerSnapHelper()
pagerSnapHelper.attachToRecyclerView(binding.recyclerViewStoryBoard)
and this is the adapter =>
class StoryBoardAdapter(
private val context: Context,
private val storyBoardList: List<StoryBoard>
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
companion object {
private const val TYPE_IMAGE = 0
private const val TYPE_VIDEO = 1
private const val BASE_URL = "Link"
}
private fun isVideo(url: String): Boolean {
val lowerUrl = url.lowercase()
return lowerUrl.endsWith(".mp4") || lowerUrl.endsWith(".webm")
}
private fun getFullUrl(relativeUrl: String): String {
return if (relativeUrl.startsWith("http")) relativeUrl else "$BASE_URL$relativeUrl"
}
override fun getItemViewType(position: Int): Int {
return if (isVideo(storyBoardList[position].imageEn)) TYPE_VIDEO else TYPE_IMAGE
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return if (viewType == TYPE_IMAGE) {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.item_story_board_image, parent, false)
ImageViewHolder(view)
} else {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.item_story_board_video, parent, false)
VideoViewHolder(view)
}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val item = storyBoardList[position]
// Check system or app language (you can replace with a stored preference if needed)
val currentLanguage = context.resources.configuration.locales[0].language
val imageUrl = if (currentLanguage == "ar") item.imageAr else item.imageEn
val fullUrl = getFullUrl(imageUrl)
if (holder is ImageViewHolder) {
Glide.with(holder.imageView.context)
.load(fullUrl)
.into(holder.imageView)
} else if (holder is VideoViewHolder) {
val videoUri = Uri.parse(fullUrl)
if (holder.videoView.tag != fullUrl) {
holder.videoView.tag = fullUrl
holder.videoView.setVideoURI(videoUri)
holder.videoView.setOnPreparedListener { mediaPlayer ->
mediaPlayer.isLooping = true
holder.videoView.start()
}
}
}
}
override fun getItemCount(): Int = storyBoardList.size
inner class ImageViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val imageView: ImageView = itemView.findViewById(R.id.imageViewItem)
}
inner class VideoViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val videoView: VideoView = itemView.findViewById(R.id.videoViewItem)
}
}
I want to show videoes in recycler view, the problem is when I swap from the first video and back to the first, the first video reloads again, I want to make all videoes loaded at once and when I swap keep the video loaded. this lines in fragment =>
// Setup StoryBoardAdapter
val storyboardAdapter = StoryBoardAdapter(requireContext(), DataRepository.storyBoardList)
val layoutManager = LinearLayoutManager(requireContext(), LinearLayoutManager.HORIZONTAL, false)
binding.recyclerViewStoryBoard.layoutManager = layoutManager
binding.recyclerViewStoryBoard.adapter = storyboardAdapter
// Attach PagerSnapHelper to show one item at a time
val pagerSnapHelper = PagerSnapHelper()
pagerSnapHelper.attachToRecyclerView(binding.recyclerViewStoryBoard)
and this is the adapter =>
class StoryBoardAdapter(
private val context: Context,
private val storyBoardList: List<StoryBoard>
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
companion object {
private const val TYPE_IMAGE = 0
private const val TYPE_VIDEO = 1
private const val BASE_URL = "Link"
}
private fun isVideo(url: String): Boolean {
val lowerUrl = url.lowercase()
return lowerUrl.endsWith(".mp4") || lowerUrl.endsWith(".webm")
}
private fun getFullUrl(relativeUrl: String): String {
return if (relativeUrl.startsWith("http")) relativeUrl else "$BASE_URL$relativeUrl"
}
override fun getItemViewType(position: Int): Int {
return if (isVideo(storyBoardList[position].imageEn)) TYPE_VIDEO else TYPE_IMAGE
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return if (viewType == TYPE_IMAGE) {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.item_story_board_image, parent, false)
ImageViewHolder(view)
} else {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.item_story_board_video, parent, false)
VideoViewHolder(view)
}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val item = storyBoardList[position]
// Check system or app language (you can replace with a stored preference if needed)
val currentLanguage = context.resources.configuration.locales[0].language
val imageUrl = if (currentLanguage == "ar") item.imageAr else item.imageEn
val fullUrl = getFullUrl(imageUrl)
if (holder is ImageViewHolder) {
Glide.with(holder.imageView.context)
.load(fullUrl)
.into(holder.imageView)
} else if (holder is VideoViewHolder) {
val videoUri = Uri.parse(fullUrl)
if (holder.videoView.tag != fullUrl) {
holder.videoView.tag = fullUrl
holder.videoView.setVideoURI(videoUri)
holder.videoView.setOnPreparedListener { mediaPlayer ->
mediaPlayer.isLooping = true
holder.videoView.start()
}
}
}
}
override fun getItemCount(): Int = storyBoardList.size
inner class ImageViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val imageView: ImageView = itemView.findViewById(R.id.imageViewItem)
}
inner class VideoViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val videoView: VideoView = itemView.findViewById(R.id.videoViewItem)
}
}
Share Improve this question edited Mar 14 at 10:34 Ahmed Salah 9812 gold badges11 silver badges33 bronze badges asked Mar 12 at 23:57 Ammar MomaniAmmar Momani 11 bronze badge3 Answers
Reset to default 0The standard behavior of RecyclerView
is to recycle the viewholder when it is not visible. In our case, it means the state of viewholder including video would get lost when you scroll. One way to disable recycling is to call setIsRecyclable(false)
on viewholder object. This way, we would lose all benefits of RecyclerView
and can impact on performance but we get the desired effect.
RecyclerView is designed to efficiently recycle ViewHolders for better memory management and performance. you can use setIsRecyclable(false)
on the ViewHolder, that will prevent recycling, it's not an ideal solution as it negates the benefits of RecyclerView.
A better approach is to use Google's ExoPlayer
:
- Maintain an ExoPlayer instance per ViewHolder to avoid reloading videos unnecessarily.
- Instead of recreating the player when scrolling, detach and reattach the player to the appropriate ViewHolder, and use some caching mechanism.
As @kirtan mentioned, you can use instance of an ExoPlayer in each ViewHolder (But there is limit for that depending upon media codec available in that device). Retain the seek position in a HashMap in your Adapter, and override 'onViewAttachedToWindow()' and 'onViewDetachedFromWindow()
' methods to pause/play the players, and save/retrieve current playing url and seekPosition in that HashMap. If the video is already played before then its loading will be faster as it will be playing from cache.
本文标签: kotlinAndroid RecyclerView to show video sliderStack Overflow
版权声明:本文标题:kotlin - Android RecyclerView to show video slider - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1744725283a2621925.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论