区别
- 相同点:都是用来更新当前的View
- 不同点:invalide实在UI线程中刷新View,要想在非UI线程中刷新View,就要用postInvalidate,因为postInvalidate底层是使用了Handler
- Android提供了Invalidate方法实现界面刷新,但是Invalidate不能直接在线程中调用,因为他是违背了单线程模型:Android UI操作并不是线程安全的,并且这些操作必须在UI线程中调用。
- invalide要在主线程调用,postInvalidate哪里都可以调用
- Invalidate调用onDraw方法,requestLayout调用onMeasure和onLayout,不一定调用onDraw
- invalidate()的调用是把之前的旧的view从主UI线程队列中pop掉
- invalidate()得在UI线程中被调动,在工作者线程中可以通过Handler来通知UI线程进行界面更新。而postInvalidate()在工作者线程中被调用
使用情景
- 利用invalidate()刷新界面
实例化一个Handler对象,并重写handleMessage方法调用invalidate()实现界面刷新;而在线程中通过sendMessage发送界面更新消息。
new Thread(new GameThread()).start();
// 实例化一个handler
Handler myHandler = new Handler() {
// 接收到消息后处理
public void handleMessage(Message msg) {
switch (msg.what) {
case Activity01.REFRESH:
mGameView.invalidate(); // 刷新界面
break;
}
super.handleMessage(msg);
}
};
class GameThread implements Runnable {
public void run() {
while (!Thread.currentThread().isInterrupted()) {
Message message = new Message();
message.what = Activity01.REFRESH;
// 发送消息
Activity01.this.myHandler.sendMessage(message);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
}
- 使用postInvalidate()刷新界面
使用postInvalidate则比较简单,不需要handler,直接在线程中调用postInvalidate即可。
使用postInvalidate则比较简单,不需要handler,直接在工作线程中调用postInvalidate即可。
class GameThread implements Runnable {
public void run() {
while (!Thread.currentThread().isInterrupted()) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
// 使用postInvalidate可以直接在工作线程中更新界面
mGameView.postInvalidate();
}
}
}
源码分析
同时postInvalidate可以指定一个延迟时间,下面我们去看看源码
/**
* <p>Cause an invalidate to happen on a subsequent cycle through the event loop.
* Use this to invalidate the View from a non-UI thread.</p>
*
* <p>This method can be invoked from outside of the UI thread
* only when this View is attached to a window.</p>
*
* @see #invalidate()
* @see #postInvalidateDelayed(long)
*/
public void postInvalidate() {
postInvalidateDelayed(0);
}
/**
* <p>Cause an invalidate to happen on a subsequent cycle through the event
* loop. Waits for the specified amount of time.</p>
*
* <p>This method can be invoked from outside of the UI thread
* only when this View is attached to a window.</p>
*
* @param delayMilliseconds the duration in milliseconds to delay the
* invalidation by
*
* @see #invalidate()
* @see #postInvalidate()
*/
public void postInvalidateDelayed(long delayMilliseconds) {
// We try only with the AttachInfo because there's no point in invalidating
// if we are not attached to our window
final AttachInfo attachInfo = mAttachInfo;
if (attachInfo != null) {
attachInfo.mViewRootImpl.dispatchInvalidateDelayed(this, delayMilliseconds);
}
}
public void dispatchInvalidateDelayed(View view, long delayMilliseconds) {
Message msg = mHandler.obtainMessage(MSG_INVALIDATE, view);
mHandler.sendMessageDelayed(msg, delayMilliseconds);
}
- requestLayout
当view确定自身已经不再适合现有的区域时,该view本身调用这个方法要求parent view(父类的视图)重新调用他的onMeasure onLayout来重新设置自己位置。特别是当view的layoutparameter发生改变,并且它的值还没能应用到view上时,这时候适合调用这个方法
调用invalidate时,它会检查上一次请求的UI重绘是否完成,如果没有完成的话,那么它就什么都不做。
void invalidateInternal(int l, int t, int r, int b, boolean invalidateCache,
boolean fullInvalidate) {
.....
//DRAWN和HAS_BOUNDS是否被设置为1,说明上一次请求执行的UI绘制已经完成,那么可以再次请求执行
if ((mPrivateFlags & (PFLAG_DRAWN | PFLAG_HAS_BOUNDS)) == (PFLAG_DRAWN | PFLAG_HAS_BOUNDS)
|| (invalidateCache && (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == PFLAG_DRAWING_CACHE_VALID)
|| (mPrivateFlags & PFLAG_INVALIDATED) != PFLAG_INVALIDATED
|| (fullInvalidate && isOpaque() != mLastIsOpaque)) {
......
final AttachInfo ai = mAttachInfo;
final ViewParent p = mParent;
final Rect damage = ai.mTmpInvalRect;
damage.set(l, t, r, b);
p.invalidateChild(this, damage);//TODO:这是invalidate执行的主体
.....
}
}
而postInvalidate则不会这样,它是向主线程发送个Message,然后handleMessage时,调用了invalidate()函数。
invalidate、postInvalidate与requestLayout浅析
简单讲下postInvalidate与invalidate的区别