幸运快艇龙虎斗
媒介屏幕刷新帧率不彊壮,掉帧严重,无法保证每秒60帧,导致屏幕画面扯破;
今天咱们来闇练下VSYNC机制和UI刷新经由
最近传言称,某知名皇冠进行大额赌博,引起不小轰动。 一、 Vsync信号详解 1、屏幕刷新关连学问点 屏幕刷新频率:一秒内屏幕刷新的次数(一秒内暴露了若干帧的图像),单元 Hz(赫兹),如常见的 60 Hz。刷新频率取决于硬件的固定参数(不会变的); 逐行扫:暴露器并不是一次性将画面暴露到屏幕上,而是从左到右边,从上到下逐行扫描,律例暴露整屏的一个个像素点,不外这一过程快到东谈主眼无法察觉到变化。以 60 Hz 刷新率的屏幕为例,这一过程即 1000 / 60 ≈ 16ms; 帧率:透露 GPU 在一秒内画图操作的帧数,单元 fps。举例在电影界接纳 24 帧的速率足够使画面运行的相称流通。而 Android 系统则接纳愈加经由的 60 fps,即每秒钟GPU最多画图 60 帧画面。帧率是动态变化的,举例当画面静止时,GPU 是莫得画图操作的,屏幕刷新的如故buffer中的数据,即GPU终末操作的帧数据; 屏幕流通度:即以每秒60帧(每帧16.6ms)的速率运行,也即是60fps,况且莫得任何蔓延或者掉帧; FPS:每秒的帧数; 丢帧:在16.6ms完成责任却因多样原因没作念完,占了后n个16.6ms的时辰,相称于丢了n帧; 2、VSYNC机制VSync机制:Android系统每隔16ms发出VSYNC信号,触发对UI进行渲染,VSync是Vertical Synchronization(垂直同步)的缩写,是一种在PC上很早就庸碌使用的手艺,不错绵薄的把它以为是一种定时中断。而在Android 4.1(JB)中一经开动引入VSync机制;
皇冠客服飞机:@seo3687
VSync机制下的画图过程;CPU/GPU经受vsync信号,Vsync每16ms一次,那么在每次发出Vsync敕令时,CPU王人会进行刷新的操作。也即是在每个16ms的第一时辰,CPU就会反应Vsync的敕令,来进行数据刷新的动作。CPU和GPU的刷新时辰,和Display的FPS是一致的。因为惟一到发出Vsync敕令的时候,CPU和GPU才会进行刷新或暴露的动作。CPU/GPU经受vsync信号提前准备下一帧要暴露的骨子,是以概况实时准备好每一帧的数据,保证画面的流通;
博彩平台注册ug环球可见vsync信号莫得教唆CPU/GPU责任的情况下,在第一个16ms之内,一切日常。关联词在第二个16ms之内,险些是在时辰段的终末CPU才野心出了数据,交给了Graphics Driver,导致GPU亦然在第二段的末尾时辰才进行了画图,所有这个词动作延后到了第三段内。从而影响了下一个画面的画图。这时会出现Jank(能干,不错相连为卡顿或者停顿)。这时候CPU和GPU可能被其他操作占用了,这即是卡顿出现的原因;
皇冠源码出租 二、UI刷新旨趣经由 1、VSYNC经由暗示当咱们通过setText更正TextView骨子后,UI界面不会坐窝更正,APP端会先向VSYNC处事请求,比及下一次VSYNC信号触发后,APP端的UI才真实开动刷新,基本经由如下:
成就setText最终调用invalidate苦求重绘,终末和会过ViewParent递归到ViewRootImpl的invalidate,请求VSYNC,在请求VSYNC的时候,会添加一个同步栅栏,防护UI线程中同步音问实施,这么作念为了加速VSYNC的反应速率,淌若不建树,VSYNC到来的时候,欧博注册官网网址投注下注正在实施一个同步音问;
2、view的invalidateView会递归的调用父容器的invalidateChild,逐级回溯,最终走到ViewRootImpl的invalidate
赌博投注View.java void invalidateInternal(int l, int t, int r, int b, boolean invalidateCache, boolean fullInvalidate) { // Propagate the damage rectangle to the parent view. final AttachInfo ai = mAttachInfo; final ViewParent p = mParent; if (p != null && ai != null && l < r && t < b) { final Rect damage = ai.mTmpInvalRect; damage.set(l, t, r, b); p.invalidateChild(this, damage); } ViewRootImpl.java void invalidate() { mDirty.set(0, 0, mWidth, mHeight); if (!mWillDrawSoon) { scheduleTraversals(); } }
ViewRootImpl会调用scheduleTraversals准备重绘,但是,重绘一般不会立即实施,而是往Choreographer的Choreographer.CALLBACK_TRAVERSAL部队中添加了一个mTraversalRunnable,同期苦求VSYNC,这个mTraversalRunnable要一直比及苦求的VSYNC到来后才会被实施;
近日,重庆市永川区萱花消防救援站25岁的消防员黎尧考上清华大学公共管理专业在职研究生的消息冲上网络热搜,人们纷纷为这位“蓝朋友”学霸点赞。
葡京博彩 3、scheduleTraversalsViewRootImpl.java // 将UI画图的mTraversalRunnable加入到下次垂直同步信号到来的恭候callback中去 // mTraversalScheduled用来保证本次Traversals未实施前,不会条目遍历双方,浪费16ms内,不需要画图两次 void scheduleTraversals() { if (!mTraversalScheduled) { mTraversalScheduled = true; // 防护同步栅栏,同步栅栏的真谛即是约束同步音问 mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier(); // postCallback的时候,趁机请求vnsc垂直同步信号scheduleVsyncLocked mChoreographer.postCallback( Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null); <!--添加一个贬责触摸事件的回调,防护中间有Touch事件过来--> if (!mUnbufferedInputDispatch) { scheduleConsumeBatchedInput(); } notifyRendererOfFramePending(); pokeDrawLockIfNeeded(); } }4、苦求VSYNC同步信号
Choreographer.java private void postCallbackDelayedInternal(int callbackType, Object action, Object token, long delayMillis) { synchronized (mLock) { final long now = SystemClock.uptimeMillis(); final long dueTime = now + delayMillis; mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token); if (dueTime <= now) { <!--苦求VSYNC同步信号--> scheduleFrameLocked(now); } } }5、scheduleFrameLocked
// mFrameScheduled保证16ms内,只会苦求一次垂直同步信号 // scheduleFrameLocked不错被调用屡次,但是mFrameScheduled保证下一个vsync到来之前,不会有新的请求发出 // 弥漫的scheduleFrameLocked调用被无效化 private void scheduleFrameLocked(long now) { if (!mFrameScheduled) { mFrameScheduled = true; if (USE_VSYNC) { if (isRunningOnLooperThreadLocked()) { scheduleVsyncLocked(); } else { // 因为invalid一经有了同步栅栏,是以必须mFrameScheduled,音问才调被UI线程实施 Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC); msg.setAsynchronous(true); mHandler.sendMessageAtFrontOfQueue(msg); } } } }在现时苦求的VSYNC到来之前,不会再去请求新的VSYNC,因为16ms内苦求两个VSYNC没真谛; 再VSYNC到来之后,Choreographer驾驭Handler将FrameDisplayEventReceiver封装成一个异步Message,发送到UI线程的MessageQueue; 6、FrameDisplayEventReceiver
private final class FrameDisplayEventReceiver extends DisplayEventReceiver implements Runnable { private boolean mHavePendingVsync; private long mTimestampNanos; private int mFrame; public FrameDisplayEventReceiver(Looper looper) { super(looper); } @Override public void onVsync(long timestampNanos, int builtInDisplayId, int frame) { long now = System.nanoTime(); if (timestampNanos > now) { <!--日常情况,timestampNanos不应该大于now,一般是上传vsync的机制出了问题--> timestampNanos = now; } <!--淌若上一个vsync同步信号没实施,那就不应该相应下一个(可能是其他线程通过某种时势请求的)--> if (mHavePendingVsync) { Log.w(TAG, "Already have a pending vsync event. There should only be " + "one at a time."); } else { mHavePendingVsync = true; } <!--timestampNanos其实是本次vsync产生的时辰,从处事端发过来--> mTimestampNanos = timestampNanos; mFrame = frame; Message msg = Message.obtain(mHandler, this); <!--由于一经存在同步栅栏,是以VSYNC到来的Message需要行为异步音问发送以前--> msg.setAsynchronous(true); mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS); } @Override public void run() { mHavePendingVsync = false; <!--这里的mTimestampNanos其实即是本次Vynsc同步信号到来的时候,但是实施这个音问的时候,可能蔓延了--> doFrame(mTimestampNanos, mFrame); } }之是以封装成异步Message,是因为前边添加了一个同步栅栏,同步音问不会被实施; UI线程被唤起,取出该音问,最终调用doFrame进行UI刷新重绘; 7、doFrame
void doFrame(long frameTimeNanos, int frame) { final long startNanos; synchronized (mLock) { <!--作念了许多东西,王人是为了保证一次16ms有一次垂直同步信号,有一次input 、刷新、重绘--> if (!mFrameScheduled) { return; // no work to do } long intendedFrameTimeNanos = frameTimeNanos; startNanos = System.nanoTime(); final long jitterNanos = startNanos - frameTimeNanos; <!--查验是否因为蔓延实施掉帧,每大于16ms,就多掉一帧--> if (jitterNanos >= mFrameIntervalNanos) { final long skippedFrames = jitterNanos / mFrameIntervalNanos; <!--跳帧,其实即是上一次请求刷新被蔓延的时辰,但是这里skippedFrames为0不代表莫得掉帧--> if (skippedFrames >= SKIPPED_FRAME_WARNING_LIMIT) { <!--skippedFrames很大一定掉帧,但是为 0,去并非没掉帧--> Log.i(TAG, "Skipped " + skippedFrames + " frames! " + "The application may be doing too much work on its main thread."); } final long lastFrameOffset = jitterNanos % mFrameIntervalNanos; <!--开动doFrame的确凿有用时辰戳--> frameTimeNanos = startNanos - lastFrameOffset; } if (frameTimeNanos < mLastFrameTimeNanos) { <!--这种情况一般是生成vsync的机制出现了问题,那就再苦求一次--> scheduleVsyncLocked(); return; } <!--intendedFrameTimeNanos是蓝本要画图的时辰戳,frameTimeNanos是确凿的,不错在渲染器具中标记蔓延VSYNC若干--> mFrameInfo.setVsync(intendedFrameTimeNanos, frameTimeNanos); <!--移除mFrameScheduled判断,阐发贬责开动了,--> mFrameScheduled = false; <!--更新mLastFrameTimeNanos--> mLastFrameTimeNanos = frameTimeNanos; } try { <!--确凿开动贬责业务--> Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Choreographer#doFrame"); <!--贬责打包的move事件--> mFrameInfo.markInputHandlingStart(); doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos); <!--贬责动画--> mFrameInfo.markAnimationsStart(); doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos); <!--贬责重绘--> mFrameInfo.markPerformTraversalsStart(); doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos); <!--提交-> doCallbacks(Choreographer.CALLBACK_COMMIT, frameTimeNanos); } finally { Trace.traceEnd(Trace.TRACE_TAG_VIEW); } }doTraversal会先将栅栏移除,然后贬责performTraversals,进行测量、布局、画图,提交现时帧给SurfaceFlinger进行图层合成暴露; 以上多个boolean变量保证了每16ms最多实施一次UI重绘; 9、UI局部重绘
View重绘刷新,并不会导致所有View王人进行一次measure、layout、draw幸运快艇龙虎斗,仅仅这个待刷新View链路需要调养,剩余的View可能不需要浪费元气心灵再来一遍;
重庆时时彩炸金花View.java public RenderNode updateDisplayListIfDirty() { final RenderNode renderNode = mRenderNode; ... if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0