简述invalidate()和postInvalidate()方法的区别和应用场景?

参考回答

invalidate()postInvalidate() 都是用来请求重新绘制视图的两种方法。它们的作用是相似的,即使得视图在下一次绘制周期中重绘,但它们的调用时机和线程之间的关系不同。

1. invalidate()

  • invalidate() 方法会立即标记视图为“需要重新绘制”,然后系统会在下一次合适的时机(通常是下一帧)进行重绘。
  • 该方法通常在 UI 线程中调用,因为它会直接请求重新绘制当前视图。

    使用场景

  • 当你在主线程中直接修改视图的内容,并希望立刻进行重绘时使用。
  • 例如,当你改变一个视图的状态或样式,需要立刻更新 UI 时:

    “`java
    view.invalidate(); // 在 UI 线程中调用
    “`

2. postInvalidate()

  • postInvalidate()invalidate() 的异步版本。它会将视图的重绘请求放入消息队列中,然后在 UI 线程空闲时处理,从而避免在非主线程中直接调用 invalidate() 时可能导致的问题。
  • postInvalidate() 可以在非 UI 线程中调用,它会延迟到主线程中执行重绘请求。

    使用场景

  • 当你在非 UI 线程中(例如后台线程)进行视图的更新,并希望进行视图重绘时使用。
  • 例如,在后台线程中更新视图时,你不能直接调用 invalidate(),因为只有 UI 线程才能更新视图。这时你应该使用 postInvalidate() 来保证重绘请求被正确地传递给 UI 线程:

    “`java
    view.postInvalidate(); // 在非 UI 线程中调用
    “`

详细讲解与拓展

1. invalidate() 方法

  • invalidate() 是直接在当前线程(通常是主线程)上执行的。当你调用 invalidate() 时,它会标记该视图为“需要重绘”,然后在下一个绘制周期中调用 onDraw() 方法重新绘制视图。
  • 如果你在 UI 线程中调用 invalidate(),那么视图会立刻被标记为需要重绘,并且重绘会在下一个事件循环中执行。
public void invalidate() {
    // 标记视图为“需要重绘”,并请求在下一个绘制周期中执行 onDraw() 方法
    invalidateParentIfNeeded();
    refreshDrawableState();
    requestLayout();
}
Java
  • 调用 invalidate() 后,视图并不会立即被重绘,而是会在当前视图层次结构中的下一次绘制周期中被重绘。
  • 如果在 onDraw() 中绘制图形或更新视图的内容,invalidate() 适用于要求视图及时更新的场景。

2. postInvalidate() 方法

  • postInvalidate() 是一个异步调用,它会将 invalidate() 的请求放入主线程的消息队列中。这样,即使你在子线程中调用 postInvalidate(),它也会确保视图更新操作发生在 UI 线程上,而不会导致线程安全问题。
public void postInvalidate() {
    // 通过消息队列安排在 UI 线程中调用 invalidate()
    post(new Runnable() {
        @Override
        public void run() {
            invalidate();
        }
    });
}
Java
  • postInvalidate() 是线程安全的,可以在任何线程中调用。它会确保视图在主线程中重绘,避免了直接在非 UI 线程中调用 invalidate() 可能导致的异常或错误。

3. 在 UI 线程和非 UI 线程中的使用

  • UI 线程:在 UI 线程中调用 invalidate() 是直接有效的,因为 invalidate() 会触发重绘过程并直接更新视图。

    例如,更新一个按钮的外观:

    button.setText("Updated");
    button.invalidate();  // UI 线程中直接调用
    
    Java
  • 非 UI 线程:在非 UI 线程(例如后台线程或子线程)中,调用 invalidate() 会导致 CalledFromWrongThreadException 异常。因此,必须通过 postInvalidate() 来确保视图的重绘请求是在 UI 线程上执行的。

    例如,后台线程中更新 UI:

    new Thread(new Runnable() {
      @Override
      public void run() {
          // 执行一些后台任务
          view.postInvalidate();  // 在非 UI 线程中正确地请求重绘
      }
    }).start();
    
    Java

4. invalidate()postInvalidate() 的关系

  • invalidate() 在当前线程中立即执行视图更新,它适用于 UI 线程。
  • postInvalidate() 是一个延迟调用,它会将视图的更新操作推到 UI 线程中。这个方法通常用于在非 UI 线程中请求视图更新。

总结

  • invalidate():用于请求重新绘制视图,适用于在 UI 线程中直接调用,能够即时生效。
  • postInvalidate():与 invalidate() 类似,但它是异步调用,适用于非 UI 线程中请求视图更新,能够保证重绘操作在 UI 线程中执行。

invalidate()postInvalidate() 主要的区别在于调用线程的限制和异步执行的方式,前者只能在 UI 线程中调用,而后者允许在任何线程中调用,并通过消息队列确保更新操作最终在 UI 线程中执行。

发表评论

后才能评论