Android 直播间动画动画队列实现

在直播软件中 需要用到各种各样的动画,大量用户赠送礼物和加入房间会产生很多的动画执行.根据不同的动画又要又要有不同的播放逻辑,这个时候就需要容器具根据不同的需求,如排序,插队,顺序,倒叙等场景去执行动画.

1:需求

  • 先进先出/先进后出 --->链表
  • 插队
  • 优先级执行 --->PriorityQueue 队列
  • 容器最大容量

2:需求分析

整理上诉需求,List 处理起来明显很处理,所以就需要用到链表和队列来处理这部分需求

  • LinkList 双向链表 插入和删除快,指定位置获取快的特点 适合先进先出和插队的操作
  • PriorityQueue 是一种基于优先级排序的队列

3:实现

3.1 FIFO/LIFO 和插队需求

需求:

  • 先进先出/先进后出
  • 插队(优先取出)
  • 容量限制(超出容量会移除后边的数据,将新数据添加进去)

实现代码:

kotlin 复制代码
/**
 * 直播动画队列
 * 动画队列顺序执行,支持 FIFO 和 LIFO 动态切换  默认先进先出
 * 可设置最大容量,超过后自动移除旧任务
 * maxQueueSize  最大容量  超出容量 会自动移除最晚执行的顺序
 *
 */
class AnimationFIFOAndLIFOQueueManager(private val maxQueueSize: Int = 100) {

    enum class Mode {
        FIFO, // 先进先出
        LIFO  // 先进后出
    }

    private val animationQueue: LinkedList<() -> Unit> = LinkedList()
    private var isRunning = false
    private var mode = Mode.FIFO

    /**
     * 设置队列模式
     */
    @Synchronized
    fun setMode(newMode: Mode) {
        mode = newMode
    }

    /**
     * 添加动画到队列,如果队列超过最大长度则移除旧动画
     */
    @Synchronized
    fun enqueue(animation: () -> Unit) {
        // 达到最大容量,移除"最老"的任务
        if (animationQueue.size >= maxQueueSize) {
            when (mode) {
                Mode.FIFO -> animationQueue.pollFirst() // FIFO 模式,移除队头(最旧)
                Mode.LIFO -> animationQueue.pollLast()  // LIFO 模式,移除队尾(最旧)
            }
        }

        // 添加新任务
        when (mode) {
            Mode.FIFO -> animationQueue.offerLast(animation)  // 队尾入队
            Mode.LIFO -> animationQueue.offerFirst(animation) // 队头入队
        }
        runNext()
    }

    /**
     * 插队:无论模式,始终插入队头
     */
    @Synchronized
    fun enqueueAtFront(animation: () -> Unit) {
        if (animationQueue.size >= maxQueueSize) {
            animationQueue.pollLast() // 插队时默认移除最尾的(最不紧急)
        }
        animationQueue.offerFirst(animation)
        runNext()
    }

    @Synchronized
    private fun runNext() {
        if (isRunning || animationQueue.isEmpty()) return
        val next = animationQueue.pollFirst() ?: return
        isRunning = true
        try {
            next()
        } catch (e: Exception) {
            isRunning = false
            runNext()
        }
    }

    /**
     * 动画完成时调用
     */
    @Synchronized
    fun onAnimationEnd() {
        isRunning = false
        runNext()
    }

    @Synchronized
    fun clear() {
        animationQueue.clear()
        isRunning = false
    }

    fun isBusy(): Boolean = isRunning
}

调用:

✅ 1. 初始化队列(默认 FIFO)

ini 复制代码
val animationQueue = AnimationFIFOAndLIFOQueueManager()

✅ 2. 添加动画任务(enqueue)

scss 复制代码
animationQueue.enqueue {
    // 这里写你的动画逻辑
    println("动画 A 开始")

    // 假设动画是异步的,比如 500ms 后结束,结束后手动回调:
    Handler(Looper.getMainLooper()).postDelayed({
        println("动画 A 结束")
        animationQueue.onAnimationEnd() // 通知队列继续下一个
    }, 500)
}

✅ 3. 插队(优先执行)

scss 复制代码
animationQueue.enqueueAtFront {
    println("插队动画 B 开始")
    Handler(Looper.getMainLooper()).postDelayed({
        println("插队动画 B 结束")
        animationQueue.onAnimationEnd()
    }, 300)
}

✅ 4. 切换 LIFO 模式(后进先出)

scss 复制代码
animationQueue.setMode(AnimationFIFOAndLIFOQueueManager.Mode.LIFO)

✅ 5. 清空队列 / 判断是否执行中

scss 复制代码
animationQueue.clear()         // 清除所有未执行动画
val busy = animationQueue.isBusy() // 判断当前是否正在执行中

3.2 优先级队列

需求:

  • 按优先级执行
  • 定制容器大小

代码实现

kotlin 复制代码
package com.qianrun.voice.common.utils.animate

import java.util.PriorityQueue

/**
 * 动画队列 等级顺序执行
 * maxSize  队列 最大容量  超过了 移除优先级最低的数据
 * priorityDescending  true:priority越大越先执行;false:priority越小越先执行
 */
class AnimationPriorityQueueManager(  private val maxSize: Int = 100 ,var priorityDescending: Boolean=true ) {
    private var sequenceCounter = 0L
    private val animationQueue: PriorityQueue<AnimationTask> = PriorityQueue()
    private var isRunning = false


    // 添加动画到队列尾部
    @Synchronized
    fun enqueue(priority: Int = 0, animation: () -> Unit) {
        val task = AnimationTask(priority, sequenceCounter++,priorityDescending, animation)
        // 加入新任务前,如果队列满了,先移除一个任务
        if (animationQueue.size >= maxSize) {
            // 移除"最旧"的任务,或者"最低优先级"的任务,依据你想要的策略
            // 这里简单移除优先级最低的(队尾元素)
            animationQueue.poll()
        }
        animationQueue.offer(task)
        runNext()
    }

    @Synchronized
    private fun runNext() {
        if (isRunning || animationQueue.isEmpty()) return

        val next = animationQueue.poll() ?: return

        isRunning = true
        try {
            next.action()
        } catch (e: Exception) {
            isRunning = false
            runNext()
        }
    }


    // 动画完成时回调此方法
    @Synchronized
    fun onAnimationEnd() {
        isRunning = false
        runNext()
    }

    // 清空队列
    @Synchronized
    fun clear() {
        animationQueue.clear()
        isRunning = false
    }

    // 当前是否有动画在运行
    fun isBusy(): Boolean = isRunning
}

调用:

✅ 1. 初始化队列

ini 复制代码
val animationQueue = AnimationPriorityQueueManager(
    maxSize = 50,
    priorityDescending = true // 优先级越大越先执行
)

✅ 2. 添加动画任务(enqueue)

scss 复制代码
animationQueue.enqueue(priority = 10) {
    println("🎬 动画 A(优先级10)开始")
    Handler(Looper.getMainLooper()).postDelayed({
        println("✅ 动画 A 结束")
        animationQueue.onAnimationEnd() // 动画结束必须调用
    }, 500)
}

animationQueue.enqueue(priority = 50) {
    println("🎬 动画 B(优先级50)开始")
    Handler(Looper.getMainLooper()).postDelayed({
        println("✅ 动画 B 结束")
        animationQueue.onAnimationEnd()
    }, 300)
}

会先执行 B(priority=50),再执行 A(priority=10)


✅ 3. 可选:清空/判断是否执行中

scss 复制代码
animationQueue.clear()             // 清空所有任务
val isRunning = animationQueue.isBusy() // 判断是否正在执行动画

✅ 4. 示例封装函数(更清爽)

你可以写个辅助函数来封装动画任务:

kotlin 复制代码
fun enqueueDemoAnimation(name: String, priority: Int, duration: Long) {
    animationQueue.enqueue(priority = priority) {
        println("🎞️ 动画 [$name] 开始(优先级=$priority)")
        Handler(Looper.getMainLooper()).postDelayed({
            println("✅ 动画 [$name] 结束")
            animationQueue.onAnimationEnd()
        }, duration)
    }
}

总结

简单实现了动画的各种队列执行,特此记录下.如有启发 ,欢迎copy

相关推荐
雨白16 小时前
Android 快捷方式实战指南:静态、动态与固定快捷方式详解
android
hqk16 小时前
鸿蒙项目实战:手把手带你实现 WanAndroid 布局与交互
android·前端·harmonyos
LING16 小时前
RN容器启动优化实践
android·react native
恋猫de小郭19 小时前
Flutter 发布官方 Skills ,Flutter 在 AI 领域再添一助力
android·前端·flutter
Kapaseker1 天前
一杯美式搞懂 Any、Unit、Nothing
android·kotlin
黄林晴1 天前
你的 Android App 还没接 AI?Gemini API 接入全攻略
android
恋猫de小郭1 天前
2026 Flutter VS React Native ,同时在 AI 时代 VS Native 开发,你没见过的版本
android·前端·flutter
冬奇Lab1 天前
PowerManagerService(上):电源状态与WakeLock管理
android·源码阅读
BoomHe2 天前
Now in Android 架构模式全面分析
android·android jetpack
二流小码农2 天前
鸿蒙开发:上传一张参考图片便可实现页面功能
android·ios·harmonyos