当前位置:网站首页>Refresh mechanism of vie
Refresh mechanism of vie
2022-06-25 02:40:00 【Dongdongxu Huster】
Preface
Usually, I only know that I am calling invalidate, requestLayout, perhaps The screen can be refreshed through animation , Achieve what you want ui effect , But yes. view I don't understand the refresh mechanism of , This paper records my thinking and summary on the following issues .
- view How often do I refresh
- view When to refresh
- view How to refresh
- If the interface doesn't change , Do you still need to refresh
- Just call invalidate, requestLayout Wait for the function to be refreshed immediately
view How often do I refresh
Android The system every 16ms Will be issued VSYNC Signal redraw our interface (Activity).
Why 16ms, because Android The set refresh rate is 60FPS(Frame Per Second), That is, every second 60 Refresh rate of frame , About us 16ms Refresh once .
For a system , Can be divided into CPU,GPU And the display ,CPU Responsible for calculation ,GPU Render the calculated data , Then put it in the buffer and save it , The display takes the rendered data at a fixed frequency and displays it . The display refresh rate is fixed , however CPU and GPU The calculation and rendering time is irregular , hypothesis GPU The rendering rate is instantaneous , The main time factor depends on CPU,CPU The process of calculation is actually View Tree drawing process , That is, start from the root layout , Traverse all view Perform measurements separately 、 Layout 、 The process of drawing , If our interface is too complex , stay 16ms The calculation is not completed within , What the monitor gets is old data , This is the frame drop , For users, they will feel stuck .

The figure above shows a typical frame dropping process .
view Refresh time
We all know invalidate(), requestLayout() The function makes view Redraw , But is redrawing started as soon as it is called ? As mentioned above VSYNC What does the signal do ?
We from View Of invalidate Function to see the whole execution process
public void invalidate(Rect dirty) {
final int scrollX = mScrollX;
final int scrollY = mScrollY;
invalidateInternal(dirty.left - scrollX, dirty.top - scrollY,
dirty.right - scrollX, dirty.bottom - scrollY, true, false);
}
invalidateInternal() Function will be called recursively parent Of invaldateChild() function , Will eventually be called to ViewRootImpl Of invalidate() Method
void invalidate() {
mDirty.set(0, 0, mWidth, mHeight);
if (!mWillDrawSoon) {
scheduleTraversals();
}
}
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
// Insert a synchronous message barrier
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
notifyRendererOfFramePending();
pokeDrawLockIfNeeded();
}
}
mTraversalRunnable It's a Runnable object , It internally executes doTraversal() Method , In this method, the traversal and drawing operations are really started , As you can see from the above code , It doesn't start drawing immediately , But through mChoreographer Object registers a callback , In this postCallback Synchronization will be requested in VSYNC Information .
private void postCallbackDelayedInternal(int callbackType,
Object action, Object token, long delayMillis) {
if (DEBUG_FRAMES) {
Log.d(TAG, "PostCallback: type=" + callbackType
+ ", action=" + action + ", token=" + token
+ ", delayMillis=" + delayMillis);
}
synchronized (mLock) {
final long now = SystemClock.uptimeMillis();
final long dueTime = now + delayMillis;
mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);
if (dueTime <= now) {
// Apply for synchronization signal
scheduleFrameLocked(now);
} else {
Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
msg.arg1 = callbackType;
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, dueTime);
}
}
}
private void scheduleFrameLocked(long now) {
if (!mFrameScheduled) {
mFrameScheduled = true;
if (USE_VSYNC) {
if (DEBUG_FRAMES) {
Log.d(TAG, "Scheduling next frame on vsync.");
}
// If running on the Looper thread, then schedule the vsync immediately,
// otherwise post a message to schedule the vsync from the UI thread
// as soon as possible.
if (isRunningOnLooperThreadLocked()) {
scheduleVsyncLocked();
} else {
Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC);
msg.setAsynchronous(true);
mHandler.sendMessageAtFrontOfQueue(msg);
}
} else {
final long nextFrameTime = Math.max(
mLastFrameTimeNanos / TimeUtils.NANOS_PER_MS + sFrameDelay, now);
if (DEBUG_FRAMES) {
Log.d(TAG, "Scheduling next frame in " + (nextFrameTime - now) + " ms.");
}
Message msg = mHandler.obtainMessage(MSG_DO_FRAME);
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, nextFrameTime);
}
}
}
Because the synchronization message barrier is added , So here we create an asynchronous MSG_DO_FRAME news , Here is a very important class FrameDisplayEventReceiver
private final class FrameDisplayEventReceiver extends DisplayEventReceiver
implements Runnable {
private boolean mHavePendingVsync;
private long mTimestampNanos;
private int mFrame;
private VsyncEventData mLastVsyncEventData = new VsyncEventData();
public FrameDisplayEventReceiver(Looper looper, int vsyncSource) {
super(looper, vsyncSource, 0);
}
// TODO(b/116025192): physicalDisplayId is ignored because SF only emits VSYNC events for
// the internal display and DisplayEventReceiver#scheduleVsync only allows requesting VSYNC
// for the internal display implicitly.
@Override
public void onVsync(long timestampNanos, long physicalDisplayId, int frame,
VsyncEventData vsyncEventData) {
try {
if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
Trace.traceBegin(Trace.TRACE_TAG_VIEW,
"Choreographer#onVsync " + vsyncEventData.id);
}
// Post the vsync event to the Handler.
// The idea is to prevent incoming vsync events from completely starving
// the message queue. If there are no messages in the queue with timestamps
// earlier than the frame time, then the vsync event will be processed immediately.
// Otherwise, messages that predate the vsync event will be handled first.
long now = System.nanoTime();
if (timestampNanos > now) {
Log.w(TAG, "Frame time is " + ((timestampNanos - now) * 0.000001f)
+ " ms in the future! Check that graphics HAL is generating vsync "
+ "timestamps using the correct timebase.");
timestampNanos = now;
}
if (mHavePendingVsync) {
Log.w(TAG, "Already have a pending vsync event. There should only be "
+ "one at a time.");
} else {
mHavePendingVsync = true;
}
mTimestampNanos = timestampNanos;
mFrame = frame;
mLastVsyncEventData = vsyncEventData;
Message msg = Message.obtain(mHandler, this);
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
}
@Override
public void run() {
mHavePendingVsync = false;
doFrame(mTimestampNanos, mFrame, mLastVsyncEventData);
}
}
This class will receive the underlying VSYNC The signal ,VSync The signal is from SurfaceFlinger Realize and send regularly ,FrameDisplayEventReceiver After receiving the signal , call onVsync Method organizes messages sent to the main thread for processing . The main content of this message is run Method doFrame() Method . in other words , We must register in advance , At the bottom VSYNC Only when the signal is generated can it be recalled to our app in , Otherwise, the signal will not be received .
So , When we call invalidate(),requestLayout(), And so on , These refresh operations will not be performed immediately , But through ViewRootImpl Of scheduleTraversals() First register with the bottom layer to listen for the next screen refresh signal event , Then when the next screen refresh signal comes , Will go through performTraversals() Ergodic rendering View Tree to perform these refresh operations .
summary
Sum up , It can be concluded that
- Only synchronization signals VSYNC The interface will be refreshed when it arrives
- UI If there is no change , The synchronization signal is not requested , The interface doesn't refresh
- Synchronous signal VSYNC You need to apply to have .
- In the same frame , If there are multiple redrawing requests ,scheduleTraversals() Will filter it out , You only need to schedule a drawing task , The next time VSYNC Only when the signal arrives will it call **performTraversals()** Traverse view Tree union redrawing .
- In order to ensure that the drawing task is performed first ,ViewRootImpl A synchronization message barrier will be inserted , Synchronization messages will not be processed , So as to ensure as much as possible that VSYNC The signal can be processed at the first time .
边栏推荐
- [analysis of STL source code] functions and applications of six STL components (directory)
- Leetcode 210: curriculum II (topological sorting)
- Migrate Oracle database from windows system to Linux Oracle RAC cluster environment (2) -- convert database to cluster mode
- |How to analyze bugs? Professional summary and analysis
- psql 列转行
- 分布式事务解决方案和代码落地
- Migrate Oracle database from windows system to Linux Oracle RAC cluster environment (4) -- modify the scanip of Oracle11g RAC cluster
- Transformers Roberta如何添加tokens
- Folding screen will become an important weapon for domestic mobile phones to share the apple market
- 当人们用互联网式的思维和视角来看待产业互联网的时候,其实已陷入到了死胡同
猜你喜欢

When they are in private, they have a sense of propriety

一线城市软件测试工资——你拖后腿了吗

Sumati gamefi ecological overview, element design in the magical world

业务与技术双向结合构建银行数据安全管理体系
![[live review] battle code pioneer phase 7: how third-party application developers contribute to open source](/img/ad/26a302ca724177e37fe123f8b75e4e.png)
[live review] battle code pioneer phase 7: how third-party application developers contribute to open source

Enlightenment of using shadergraph to make edge fusion particle shader

背了八股文,六月赢麻了……

Is it out of reach to enter Ali as a tester? Here may be the answer you want

分布式事务解决方案和代码落地

会自动化—10K,能做自动化—20K,你搞懂自动化测试没有?
随机推荐
vim的Dirvish中文文档
使用ShaderGraph制作边缘融合粒子Shader的启示
When an interface has an exception, how do you analyze the exception?
Summary of knowledge points of computer level III (database) test preparation topics
Using qdomdocument to manipulate XML files in QT
Groovy之高级用法
Intranet learning notes (7)
都2022年了,你还不了解什么是性能测试?
Advanced usage of groovy
Kaggle 专利匹配比赛赛后总结
Leecode learning notes - the shortest path for a robot to reach its destination
Migrate Oracle database from windows system to Linux Oracle RAC cluster environment (3) -- set the database to archive mode
【Proteus仿真】Arduino UNO+继电器控制照明设备
【FPGA】串口以命令控制温度采集
计网 | 【四 网络层】知识点及例题
Once beego failed to find bee after passing the go get command Exe's pit
After reciting the eight part essay, I won the hemp in June
Use of hashcat
Detailed explanation of cache (for the postgraduate entrance examination of XD)
Enlightenment of using shadergraph to make edge fusion particle shader