Skip to content

PAG 动画在 Android 上只播放一次无法循环,iOS 正常。影响所有循环模式包括 REPEAT_COUNT_LOOP (-1)。#102

Open
yhuang-aeomo wants to merge 5 commits intolibpag:mainfrom
yhuang-aeomo:main
Open

PAG 动画在 Android 上只播放一次无法循环,iOS 正常。影响所有循环模式包括 REPEAT_COUNT_LOOP (-1)。#102
yhuang-aeomo wants to merge 5 commits intolibpag:mainfrom
yhuang-aeomo:main

Conversation

@yhuang-aeomo
Copy link
Copy Markdown


PR Summary

Problem

PAG 动画在 Android 上只播放一次无法循环,iOS 正常。影响所有循环模式包括 REPEAT_COUNT_LOOP (-1)。

Changes (5 commits)

  1. FlutterPagPlayer.java — 核心修复,重写动画驱动

用 Choreographer 替换 ValueAnimator:

  • 移除 ValueAnimator、AnimatorListenerAdapter、AnimatorUpdateListener 全部相关代码
  • 新增 Choreographer.FrameCallback,与 iOS CADisplayLink 方式完全对齐
  • updateFrame() 方法基于 System.nanoTime() 计算 elapsed time,手动推导 progress:
    • repeatCount < 0 → 永远走循环分支(无限循环)
    • repeatCount >= 0 && count >= repeatCount → 动画结束
  • init() 中初始帧渲染改为直接调用 super.flush()(不经过异步 post)
  • 新增 setFrameUpdateCallback(Runnable) 用于通知 Flutter 纹理系统有新帧
  • start()/stop()/pause()/cancel()/release() 全部改为操作 Choreographer
  1. FlutterPagPlugin.java — 修复 Flutter 帧通知机制

移除 setOnFrameAvailableListener 覆盖(根本原因):

  • 删除通过反射获取 Flutter 内部 onFrameListener 的代码(在新版 Flutter 上 NoSuchFieldException)
  • 删除 surfaceTexture.setOnFrameAvailableListener() 调用 — 不再覆盖 Flutter 引擎的内部帧监听器
  • 改为通过 pagPlayer.setFrameUpdateCallback() 发送 notifyFrameReady

移除 v1 Embedding 兼容代码:

  • 删除 registerWith(Registrar) 方法(Flutter v1 embedding 已废弃)
  • 删除 PluginRegistry.Registrar 相关字段和 import
  • 删除 registrar.lookupKeyForAsset 分支,仅保留 flutterAssets
  1. build.gradle — 依赖升级和构建配置
  • libpag 升级 4.3.68 → 4.5.42(修复 buffer 管理 bug)
  • 添加 namespace 'com.agl.pag'(AGP 8.0+ 要求)
  • 添加 kotlinOptions { jvmTarget = '1.8' }
  1. AndroidManifest.xml
  • 移除 package 属性(已迁移到 build.gradle 的 namespace)

huangyunan and others added 5 commits January 30, 2026 14:23
Root cause: two issues combined to prevent animation looping.

1. Replace ValueAnimator with Choreographer for animation driving.
   ValueAnimator's repeat mechanism was unreliable on Android.
   Now uses Choreographer (equivalent to iOS CADisplayLink) with
   manual elapsed-time-based progress calculation, matching iOS
   implementation exactly.

2. Remove setOnFrameAvailableListener override in FlutterPagPlugin.
   The plugin was replacing Flutter's internal SurfaceTexture frame
   listener. It tried to preserve the original via reflection, but
   this fails on newer Flutter versions (NoSuchFieldException:
   onFrameListener), causing Flutter to never receive new frame
   notifications after the first animation cycle.

3. Upgrade libpag from 4.3.68 to 4.5.42 for buffer management fixes.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant