以下是关于 postInvalidateOnAnimation


一、什么是 postInvalidateOnAnimation

postInvalidateOnAnimation 是 Android View 中用于在下一帧动画刷新时请求重绘界面的方法。

定义:

public void postInvalidateOnAnimation()

这是一个非阻塞的、异步的重绘请求,与 invalidate() 类似,但它会在下一帧的动画帧(VSync 信号)到达时触发 UI 刷新,从而提供更高效的 UI 更新

常用场景:

  • 当你需要在动画中重绘 View 时(例如:在 ValueAnimatorObjectAnimator 动画中更新 View 的状态)。
  • 使用 Choreographer 控制重绘的节奏,避免不必要的重绘。
  • 用于提高性能和流畅性,避免不必要的 CPU 开销。

二、postInvalidateOnAnimationinvalidate() 的区别

方法

触发时间

是否异步

性能

invalidate()

立刻刷新 View

否(同步调用)

UI 可能会多次重绘,增加性能开销

postInvalidate()

立刻请求重绘

是(异步调用)

使用消息队列请求重绘,下一帧刷新

postInvalidateOnAnimation()

下一帧刷新

是(异步调用)

依赖 VSync 信号,更高效、更节能

为什么 postInvalidateOnAnimation 更高效?

  • postInvalidateOnAnimation 依赖于 Choreographer,它与 Android 的 VSync 信号同步,只在 VSync 到来时重绘,节省了 CPU 资源。
  • invalidate() 会立即标记 View 需要重绘,但可能被多次调用,导致性能浪费。
  • 适用于动画驱动的 View 重绘,如进度条、运动的图形、游戏元素等。

三、如何使用 postInvalidateOnAnimation

使用示例 1:在自定义 View 中手动重绘

public class CustomView extends View {
    private float radius = 50f; // 动态半径
    private Paint paint;

    public CustomView(Context context) {
        super(context);
        paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        paint.setColor(Color.RED);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        // 绘制一个动态变化的圆
        canvas.drawCircle(getWidth() / 2f, getHeight() / 2f, radius, paint);
    }

    public void increaseRadius() {
        radius += 10f;
        // 下一帧动画时重绘
        postInvalidateOnAnimation();
    }
}

说明:

  1. 每次调用 increaseRadius()不会立即重绘,而是在下一帧 VSync 到来时重绘
  2. 这种做法比直接调用 invalidate() 更高效,避免了 UI 线程的多次重绘。

使用示例 2:结合 ValueAnimator 动画刷新 View

public class AnimatedCircleView extends View {
    private float radius = 50f; // 半径
    private Paint paint;

    public AnimatedCircleView(Context context) {
        super(context);
        paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        paint.setColor(Color.BLUE);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        // 绘制一个动态变化的圆
        canvas.drawCircle(getWidth() / 2f, getHeight() / 2f, radius, paint);
    }

    public void startAnimation() {
        ValueAnimator animator = ValueAnimator.ofFloat(50f, 200f);
        animator.setDuration(2000); // 动画持续 2 秒
        animator.addUpdateListener(animation -> {
            radius = (float) animation.getAnimatedValue();
            postInvalidateOnAnimation(); // 在 VSync 信号到达时重绘
        });
        animator.start();
    }
}

说明:

  • ValueAnimatoronUpdate 回调中,每次动画帧都会调用 postInvalidateOnAnimation()动画流畅不卡顿
  • 这是最常见的与动画配合的重绘方案,与 invalidate() 不同,不会造成多次重绘开销

四、深入理解实现原理

1. VSync(垂直同步)信号

  • Android 系统的 VSync 是一种显示刷新同步信号,它的频率通常是 60Hz(每秒 60 帧)。
  • VSync 的作用是避免图像撕裂,并控制 UI 更新的节奏
  • postInvalidateOnAnimation() 会将重绘请求插入到 Choreographer 帧队列 中,等待下一次 VSync 到来。

2. Choreographer 机制

  • Choreographer 是 Android 中的时间调度器,它与 VSync 信号同步。
  • Choreographer 负责调用 doFrame(long frameTimeNanos),并在每一帧执行 View 的重绘、动画和 UI 事件。
  • postInvalidateOnAnimation() 使用的就是 Choreographer.postFrameCallback()

源码简化版:

public void postInvalidateOnAnimation() {
    ViewRootImpl viewRoot = getViewRootImpl();
    if (viewRoot != null) {
        viewRoot.invalidate();
    } else {
        Choreographer.getInstance().postFrameCallback(new FrameCallback() {
            @Override
            public void doFrame(long frameTimeNanos) {
                invalidate();
            }
        });
    }
}

解释:

  • ViewRootImpl.invalidate():如果 View 已经附加到窗口,直接请求 ViewRoot 重绘。
  • Choreographer.postFrameCallback():如果 View 没有附加到窗口,则在下一个 VSync 到来时重绘。

五、常见的使用场景

场景

为什么使用 postInvalidateOnAnimation

自定义 View 动画

避免 View 在动画中频繁调用 invalidate()

游戏中的角色移动

在 VSync 信号到来时重绘,减少 GPU 和 CPU 占用

高频率动画效果

动画逻辑的重绘与 VSync 同步,动画流畅不卡顿

圆形进度条/动态加载条

保证进度条更新与屏幕刷新同步,避免卡顿


六、常见的面试问题

  1. postInvalidateOnAnimationinvalidate 的区别?
  • invalidate() 会立刻刷新 View,而 postInvalidateOnAnimation() 只在 VSync 信号到来时刷新,性能更高,节省资源
  1. 为什么要使用 VSync?
  • VSync 可以同步显示刷新,防止屏幕撕裂,节省 CPU 和 GPU 开销
  1. Choreographer 是什么?
  • Choreographer 是 Android 中的全局调度器,用于在每一帧中调用 View 重绘、动画和事件回调。

七、简单的博客范文

标题:详解 postInvalidateOnAnimation:高效重绘 View 的利器

前言

在 Android 开发中,invalidate() 是我们常用的请求 View 重绘的方法,但在动画场景中,频繁调用 invalidate() 会导致高 CPU 占用和不流畅的动画。为了更高效地更新 View,Android 提供了**postInvalidateOnAnimation**。

正文
  1. 什么是 postInvalidateOnAnimation
  2. postInvalidateOnAnimationinvalidate 的区别?
  3. 如何使用?(示例)
  4. 原理解析:VSync 和 Choreographer
  5. 常见场景:游戏、动画、进度条

如果你希望对博客的内容和结构有更多的调整,请告诉我!我可以为你定制一篇完整的技术博客。 😊