如何打乱Firebase获取的有序数据并实现随机展示?
Firebase视频数据随机展示实现问题
从Firebase中按顺序获取视频数据,希望随机展示这些数据,但打乱Firebase返回数据时遇到了问题。以下是相关代码:
现有代码
Main Activity
class MainActivity : AppCompatActivity() { lateinit var viewPager2:ViewPager2 lateinit var adapter:VideoAdapter override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) /**set fullscreen*/ window.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN) /**set find id*/ viewPager2 = findViewById(R.id.vpager) /**set database*/ val mDataBase = Firebase.database.getReference("videos") val options = FirebaseRecyclerOptions.Builder<VideoModel>() .setQuery(mDataBase,VideoModel::class.java) .build() /**set adapter*/ adapter = VideoAdapter(options) viewPager2.adapter = adapter } override fun onStart() { super.onStart() adapter.startListening() } override fun onStop() { super.onStop() adapter.stopListening() } }
VideoAdapter
class VideoAdapter(options: FirebaseRecyclerOptions<VideoModel?>) : FirebaseRecyclerAdapter<VideoModel?, VideoAdapter.MyViewHolder?>(options) { override fun onBindViewHolder(holder: MyViewHolder, position: Int, model: VideoModel) { holder.setdata(model) } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder { val view: View = LayoutInflater.from(parent.context).inflate(R.layout.single_video_row, parent, false) return MyViewHolder(view) } inner class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { var videoView: VideoView var title: TextView var desc: TextView var pbar: ProgressBar var fav :ImageView var isFav = false fun setdata(obj: VideoModel) { videoView.setVideoPath(obj.url) title.setText(obj.title) desc.setText(obj.desc) videoView.setOnPreparedListener { mediaPlayer -> pbar.visibility = View.GONE mediaPlayer.start() } videoView.setOnCompletionListener { mediaPlayer -> mediaPlayer.start() } fav.setOnClickListener { if (!isFav){ fav.setImageResource(R.drawable.ic_fill_favorite) isFav = true } else{ fav.setImageResource(R.drawable.ic_favorite) isFav = false } } } init { videoView = itemView.findViewById<View>(R.id.videoView) as VideoView title = itemView.findViewById<View>(R.id.textVideoTitle) as TextView desc = itemView.findViewById<View>(R.id.textVideoDescription) as TextView pbar = itemView.findViewById<View>(R.id.videoProgressBar) as ProgressBar fav = itemView.findViewById(R.id.favorites) as ImageView count = itemView.findViewById(R.id.count) as TextView } } }
VideoModel
data class VideoModel( var title:String?=null, var desc:String?=null, var url:String?=null )
Firebase中存储的视频数据包含title(标题)、desc(描述)、url(播放地址)三个字段。
解决方案
方法一:本地加载后打乱数据(适合小数据量场景)
FirebaseRecyclerAdapter直接绑定实时数据流,无法直接打乱顺序,可先将所有数据加载到本地列表,打乱后用普通RecyclerView Adapter展示:
- 修改MainActivity,监听数据变化并打乱列表
class MainActivity : AppCompatActivity() { lateinit var viewPager2: ViewPager2 lateinit var adapter: VideoAdapter private val videoList = mutableListOf<VideoModel>() private val mDatabase = Firebase.database.getReference("videos") override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) window.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN) viewPager2 = findViewById(R.id.vpager) adapter = VideoAdapter(videoList) viewPager2.adapter = adapter // 监听Firebase数据变化 mDatabase.addValueEventListener(object : ValueEventListener { override fun onDataChange(snapshot: DataSnapshot) { videoList.clear() snapshot.children.forEach { child -> val video = child.getValue(VideoModel::class.java) video?.let { videoList.add(it) } } // 打乱列表 videoList.shuffle() adapter.notifyDataSetChanged() } override fun onCancelled(error: DatabaseError) { // 处理数据读取错误 } }) } }
- 修改VideoAdapter为普通RecyclerView Adapter
class VideoAdapter(private val videoList: List<VideoModel>) : RecyclerView.Adapter<VideoAdapter.MyViewHolder>() { override fun onBindViewHolder(holder: MyViewHolder, position: Int) { holder.setdata(videoList[position]) } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder { val view = LayoutInflater.from(parent.context).inflate(R.layout.single_video_row, parent, false) return MyViewHolder(view) } override fun getItemCount() = videoList.size inner class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { private val videoView: VideoView = itemView.findViewById(R.id.videoView) private val title: TextView = itemView.findViewById(R.id.textVideoTitle) private val desc: TextView = itemView.findViewById(R.id.textVideoDescription) private val pbar: ProgressBar = itemView.findViewById(R.id.videoProgressBar) private val fav: ImageView = itemView.findViewById(R.id.favorites) private var isFav = false fun setdata(obj: VideoModel) { videoView.setVideoPath(obj.url) title.text = obj.title desc.text = obj.desc videoView.setOnPreparedListener { mediaPlayer -> pbar.visibility = View.GONE mediaPlayer.start() } videoView.setOnCompletionListener { mediaPlayer -> mediaPlayer.start() } fav.setOnClickListener { isFav = !isFav fav.setImageResource(if (isFav) R.drawable.ic_fill_favorite else R.drawable.ic_favorite) } } } }
方法二:Firebase端添加随机排序字段(适合大数据量场景)
给每条视频添加随机数值字段,通过Firebase查询时按该字段排序,实现随机返回:
- 更新VideoModel,添加random字段
data class VideoModel( var title: String? = null, var desc: String? = null, var url: String? = null, var random: Double? = null )
上传视频时,给每条视频设置
random值(比如用Math.random()生成0-1之间的随机数)。修改MainActivity中的查询逻辑
val options = FirebaseRecyclerOptions.Builder<VideoModel>() .setQuery(mDataBase.orderByChild("random"), VideoModel::class.java) .build()
方案对比
- 方法一:实现简单,无需修改Firebase数据结构;但需加载全部数据到本地,数据量大时内存开销高,实时更新需重新打乱。
- 方法二:无需本地加载全部数据,适合大数据量;但需维护额外字段,随机性依赖随机字段的分布均匀度。
内容的提问来源于stack exchange,提问作者Yugant Jha
相关产品推荐
相关产品推荐

