精华内容
下载资源
问答
  • android 屏幕刷新率
    千次阅读
    2021-06-07 18:05:08

    屏幕刷新率检查app是一款可以帮助用户了解自己手机刷新率的软件,虽然屏幕刷新率对手机整体的性能没有影响,但是对于用户的眼睛视力还是有影响的,据说,刷新率越高,那么对眼睛也会更好,可以减少对视力的伤害,对于经常打游戏的用户而言,手机的屏幕刷新率越高,对画质也会更好。

    屏幕刷新率检查app软件功能:

    1、可以帮助用户检测出自己手机屏幕刷新率的情况,让用户对自己的手机有更全面的了解;

    2、通过刷新率的检测,可以让用户合理安排使用手机的时间,减少对视力的伤害;

    3、将显示你的屏幕刷新率,新设备的刷新率如48Hz,60Hz,90Hz,120Hz,140Hz及更高。

    屏幕刷新率检查app软件特色:

    1、只需打开软件就可以轻松知道你的手机屏幕刷新率了,十分便捷;

    2、手机屏幕的刷新率越高,对眼睛越好,因为屏幕没有闪烁感;

    3、屏幕刷新率的单位是赫兹,主要是为了调整屏幕闪烁、清晰度用的。

    屏幕刷新率检查app软件点评:

    在这个刷新手机应用中,fps和hz是不同的东西,你可以与其他手机进行fps比较。例如:120帧与60帧的比较。

    更多相关内容
  • Android屏幕刷新机制

    2022-04-07 13:07:07
    Android屏幕刷新机制 一些前置概念 屏幕刷新率 一秒内屏幕刷新的次数(一秒内显示了多少帧的图像),单位 Hz(赫兹),如常见的 60 Hz,90Hz,120Hz(高刷新率)。刷新频率取决于硬件的固定参数(不会变的)。 ...

    Android屏幕刷新机制

    一些前置概念

    • 屏幕刷新率

    一秒内屏幕刷新的次数(一秒内显示了多少帧的图像),单位 Hz(赫兹),如常见的 60 Hz,90Hz,120Hz(高刷新率)。刷新频率取决于硬件的固定参数(不会变的)。

    • 逐行扫描

    显示器并不是一次性将画面显示到屏幕上,而是从左到右边,从上到下逐行扫描,顺序显示整屏的一个个像素点,不过这一过程快到人眼无法察觉到变化。以 60 Hz 刷新率的屏幕为例,这一过程即 1000 / 60 ≈ 16ms。

    • 帧率 (Frame Rate)

    表示 GPU 在一秒内绘制操作的帧数,单位 fps。例如在电影界采用 24 帧的速度足够使画面运行的非常流畅。而 Android 系统则采用更加流程的 60 fps,即每秒钟GPU最多绘制 60 帧画面。帧率是动态变化的,例如当画面静止时,GPU 是没有绘制操作的,屏幕刷新的还是buffer中的数据,即GPU最后操作的帧数据。

    • 画面撕裂

    一个屏幕内的数据来自2个不同的帧,画面会出现撕裂感,如下图

    在这里插入图片描述

    双缓存

    画面撕裂原因

    屏幕刷新频是固定的,比如每16.6ms从buffer取数据显示完一帧,理想情况下帧率和刷新频率保持一致,即每绘制完成一帧,显示器显示一帧。但是CPU/GPU写数据是不可控的,所以会出现buffer里有些数据根本没显示出来就被重写了,即buffer里的数据可能是来自不同的帧的, 当屏幕刷新时,此时它并不知道buffer的状态,因此从buffer抓取的帧并不是完整的一帧画面,即出现画面撕裂。

    简单说就是在显示的过程中,这个画面显示了不同帧的数据。正常来讲就是一个画面显示一帧的数据,现在这个画面有不同帧的数据,也就导致了画面有一个地方撕裂了。

    双缓存

    那咋解决画面撕裂呢? 答案是使用 双缓存+VSync

    由于图像绘制和屏幕读取 使用的是同个buffer,所以屏幕刷新时可能读取到的是不完整的一帧画面。

    双缓存,让绘制和显示器拥有各自的buffer:GPU 始终将完成的一帧图像数据写入到 BackBuffer,而显示器使用 FrameBuffer,当屏幕刷新时,Frame Buffer 并不会发生变化,当Back buffer准备就绪后,它们才进行交换。

    VSync

    问题又来了:什么时候进行两个buffer的交换呢?

    假如是 Backbuffer准备完成一帧数据以后就进行,那么如果此时屏幕还没有完整显示上一帧内容的话,肯定是会出问题的。看来只能是等到屏幕处理完一帧数据后,才可以执行这一操作了。

    当扫描完一个屏幕后,设备需要重新回到第一行以进入下一次的循环,此时有一段时间空隙,称为VerticalBlanking Interval(VBI)。那,这个时间点就是我们进行缓冲区交换的最佳时间。因为此时屏幕没有在刷新,也就避免了交换过程中出现 screen tearing的状况。

    VSync(垂直同步)是VerticalSynchronization的简写,它利用VBI时期出现的vertical sync pulse(垂直同步脉冲)来保证双缓冲在最佳时间点才进行交换。另外,交换是指各自的内存地址,可以认为该操作是瞬间完成。大概就是下面这幅图的样子

    在这里插入图片描述

    Android屏幕刷新机制

    Android4.1之前的问题

    具体到Android中,在Android4.1之前,屏幕刷新也遵循上面介绍的 双缓存+VSync 机制。

    对于没采用VSYNC做调度的系统来说,比如Project Butter之前的系统(4.1以下),CPU的对于显示帧的处理是凌乱的,优先级也没有保障,处理完一帧后,CPU可能并不会及时处理下一帧,可能会优先处理其他消息,等到它开始处理UI生成帧的时候,可能已经处于VSYNC的中间,这样就很容易跨两个VYSNC信号,导致掉帧。如下图:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-v5eBgjEg-1649308000110)(2.1%20%E5%9F%BA%E7%A1%80%E6%A6%82%E5%BF%B5.assets/webp-16493071346573.webp)]

    以时间的顺序来看下将会发生的过程:

    1. Display显示第0帧数据,此时CPU和GPU渲染第1帧画面,且在Display显示下一帧前完成
    2. 因为渲染及时,Display在第0帧显示完成后,也就是第1个VSync后,缓存进行交换,然后正常显示第1帧
    3. 接着第2帧开始处理,是直到第2个VSync快来前才开始处理的。
    4. 第2个VSync来时,由于第2帧数据还没有准备就绪,缓存没有交换,显示的还是第1帧。这种情况被Android开发组命名为“Jank”,即发生了丢帧
    5. 当第2帧数据准备完成后,它并不会马上被显示,而是要等待下一个VSync 进行缓存交换再显示。

    所以总的来说,就是屏幕平白无故地多显示了一次第1帧。

    原因是 第2帧的CPU/GPU计算 没能在VSync信号到来前完成 。

    我们知道,双缓存的交换 是在Vsyn到来时进行,交换后屏幕会取Frame buffer内的新数据,而实际 此时的Back buffer 就可以供GPU准备下一帧数据了。 如果 Vsyn到来时 CPU/GPU就开始操作的话,是有完整的16.6ms的,这样应该会基本避免jank的出现了(除非CPU/GPU计算超过了16.6ms)。

    drawing with VSync

    为了优化显示性能,Google在Android 4.1系统中对Android Display系统进行了重构,实现了Project Butter(黄油工程):系统在收到VSync pulse后,将马上开始下一帧的渲染。即一旦收到VSync通知(16ms触发一次),CPU和GPU 才立刻开始计算然后把数据写入buffer。如下图:

    在这里插入图片描述

    CPU/GPU根据VSYNC信号同步处理数据,可以让CPU/GPU有完整的16ms时间来处理数据,减少了jank。

    一句话总结,VSync同步使得CPU/GPU充分利用了16.6ms时间,减少jank。

    VSYNC+双缓冲在理想情况下是没有问题的,但如果某个环节出现问题,那就不一样了如下(帧耗时超过16ms)如下图:

    在这里插入图片描述

    1. 在第二个时间段内,但却因 GPU 还在处理 B 帧,缓存没能交换,导致 A 帧被重复显示。
    2. 而B完成后,又因为缺乏VSync pulse信号,它只能等待下一个signal的来临。于是在这一过程中,有一大段时间是被浪费的。
    3. 当下一个VSync出现时,CPU/GPU马上执行操作(A帧),且缓存交换,相应的显示屏对应的就是B。这时看起来就是正常的。只不过由于执行时间仍然超过16ms,导致下一次应该执行的缓冲区交换又被推迟了——如此循环反复,便出现了越来越多的“Jank”。

    可以看到在第二个阶段,存在CPU资源浪费,为什么呢?双缓冲Surface只会提供两个Buffer,一个Buffer被DisPlay占用(SurfaceFlinger用完后不会释放当前的Buffer,只会释放旧的Buffer,直观的想一下,如果新Buffer生成受阻,那么肯定要保留一个备份给SF用,才能不阻碍合成显示,就必定要一直占用一个Buffer,新的Buffer来了才释放老的),另一个被GPU处理占用,所以,CPU就无法获取到Buffer处理当前UI,在Jank的阶段空空等待。

    三缓存

    三缓存就是在双缓冲机制基础上增加了一个 Graphic Buffer 缓冲区,这样可以最大限度的利用空闲时间,带来的坏处是多使用的一个 Graphic Buffer 所占用的内存。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bUoxhFWa-1649308000111)(2.1%20%E5%9F%BA%E7%A1%80%E6%A6%82%E5%BF%B5.assets/webp-16493075795379.webp)]

    如上图所示,虽然即使每帧需要20ms(CPU 8ms +GPU 12ms),但是由于多加了一个Buffer,实现了CPU跟GPU并行,便可以做到了只在开始掉一帧,后续却不掉帧,双缓冲充分利用16ms做到低延时,三缓冲保障了其稳定性。

    以上就是Android屏幕刷新的原理了。

    总结

    • 同步是防止画面撕裂的关键,VSYNC同步+双缓冲能防止画面撕裂
    • VSYNC+双缓冲在Android中能有序规划渲染流程,降低延时
    • Android已经采用了双缓冲,双缓冲不仅仅是两份存储,它是一个概念,双缓冲是一条链路,不是某一个环节,是整个系统采用的一个机制,需要各个环节的支持,从APP到SurfaceFlinger、到图像显示都要参与协作。
    • 三缓冲在UI复杂情况下能保证画面的连续性,提高柔韧性。

    参考:“终于懂了” 系列:Android屏幕刷新机制—VSync、Choreographer 全面理解!

    展开全文
  • Android刷新率设置

    千次阅读 2021-04-28 13:38:54
    传统的手机屏幕刷新率通常为60Hz,但从2020年各大手机厂商发布的手机来看,高刷新率已经是不可逆的趋势。然而由于高刷新率在带来流畅体验的同时,也会导致更高的功耗,因此支持高刷新率的手机通常也支持刷新率设置,...

    0 前言

        传统的手机屏幕刷新率通常为60Hz,但从2020年各大手机厂商发布的手机来看,高刷新率已成为不可逆的趋势,目前最高刷新率达144Hz[1]。然而由于高刷新率在带来流畅体验的同时,也会导致更高的功耗,因此支持高刷新率的手机通常也支持刷新率设置,档位数量从2档到7档不等。Android也只支持APP设置刷新率的,可以预测,后续APP根据需要来调节刷新率就像现在的视频APP根据需要来调节背光一样平常。

        API 21(Android-5.0)新增preferredRefreshRate以支持APP设置刷新率,API 23(Android-6.0)后被preferredDisplayModeId取代[2],后者沿用到API 30(Android-11)。此外,Android-11还新增了setFrameRate()用于设置刷新率。

    1 查看

        Android-10之前原生系统只能通过命令查看刷新率:

    adb shell "dumpsys SurfaceFlinger | grep cur:"

       Android-11原生系统可通过开发者模式打开“Show refresh rate”功能,然后就会在屏幕左上角显示当前的刷新率:

    展开全文
  • Android屏幕刷新机制原理分析

    千次阅读 2021-11-14 13:27:54
    看完上面的流程图,我们很容易想到一个问题,屏幕是以16.6ms的固定频率进行刷新的,但是我们应用层触发绘制的时机是完全随机的(比如我们随时都可以触摸屏幕触发绘制),如果在GPU向缓冲区写入数据的同时,屏幕也在...
    基本概念

    CPU:执行应用层的measure、layout、draw等操作,绘制完成后,将数据交由GPU
    GPU:处理数据,将数据发送到缓冲区
    屏幕:由一个一个像素组成,以固定频率(1000ms,60次,即16.6ms一次)去缓冲区里读取数据填充像素点
    在这里插入图片描述

    双缓冲机制

    看完上面的流程图,我们很容易想到一个问题,屏幕是以16.6ms的固定频率进行刷新的,但是我们应用层触发绘制的时机是完全随机的(比如我们随时都可以触摸屏幕触发绘制),如果在GPU向缓冲区写入数据的同时,屏幕也在向缓冲区读取数据,会发生什么情况呢?有可能屏幕上就会出现一部分是前一帧的画面,一部分是另一帧的画面,这显然是无法接受的,那怎么解决这个问题呢?
    所以,在屏幕刷新中,Android系统引入了双缓冲机制。GPU只向Back Buffer中写入绘制数据,且GPU会定期交换Back Buffer和Frame Buffer,也就是让Back Buffer 变成Frame Buffer交给屏幕进行绘制,让原先的Frame Buffer变成Back Buffer进行数据写入。交换的频率也是60次/秒,这就与屏幕的刷新频率保持了同步
    在这里插入图片描述

    VSync - 垂直同步信号

    vsync是固定频率的脉冲信号,屏幕根据这个信号周期性的刷新,屏幕每次收到这个信号,就从屏幕缓存区读取一帧的图像数据进行显示,而绘制是由应用端(任何时候都有可能)发起的,如果屏幕收到vsync信号,但是这一帧的还没有绘制完,就会显示上一帧的数据,这并不是因为绘制这一帧的时间过长(超过了信号发送周期),只是信号快来的时候才开始绘制,如果频繁的出现的这种情况,用户就会感知屏幕的卡顿,即使绘制时间优化的再好也无济于事,因为这是底层刷新机制的缺陷。如下图,2就会被丢失,即所谓的丢帧。
    在这里插入图片描述

    当然系统提供了解决方案,如果绘制和vsync信号同步就好了,每次收到vsync信号时,一方面屏幕获取图像数据刷新界面,另一方面应用开始绘制准备下一帧图像数据。如果优化的好,每一帧图像绘制控制在16ms以内,就可以非常流畅了。那么问题来了,应用层view的重绘一般调用requestLayout触发,这个函数随时都能调用,如何控制只在vsync信号来时触发重绘呢?有一个关键类Choreography(舞蹈指导,编舞),它最大的作用就是你往里面发送一个消息,这个消息最快也要等到下一个vsync信号来的时候触发。比如说绘制可能随时发起,封装一个Runnable丢给Choreography,下一个vsync信号来的时候,开始处理消息,然后真正的开始界面的重绘了。相当于UI绘制的节奏完全由Choreography来控制。
    在这里插入图片描述

    Choreography原理分析

    从ViewRootImpl#requestLayout刷新UI开始看起

    @Override
    public void requestLayout() {
        if (!mHandlingLayoutInLayoutRequest) {
            // 检查线程
            checkThread();
            mLayoutRequested = true;
            scheduleTraversals();
        }
    }
    
    void scheduleTraversals() {
        if (!mTraversalScheduled) {
            mTraversalScheduled = true;
            // 发送一个同步屏障信号,等下再来解释这个信号的作用
            mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
            // 核心,调用postCallback,把一个Runnable传进去
            mChoreographer.postCallback(
                    Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
            if (!mUnbufferedInputDispatch) {
                scheduleConsumeBatchedInput();
            }
            notifyRendererOfFramePending();
            pokeDrawLockIfNeeded();
        }
    }
    
    // Choreographer类
    public void postCallback(int callbackType, Runnable action, Object token) {
        postCallbackDelayed(callbackType, action, token, 0);
    }
    
    public void postCallbackDelayed(int callbackType,
            Runnable action, Object token, long delayMillis) {
        if (action == null) {
            throw new IllegalArgumentException("action must not be null");
        }
        if (callbackType < 0 || callbackType > CALLBACK_LAST) {
            throw new IllegalArgumentException("callbackType is invalid");
        }
    
        postCallbackDelayedInternal(callbackType, action, token, delayMillis);
    }
    
    private void postCallbackDelayedInternal(int callbackType,
            Object action, Object token, long delayMillis) {
        synchronized (mLock) {
            final long now = SystemClock.uptimeMillis();
            final long dueTime = now + delayMillis;
            // 把Runnable的回调,添加到CallbackQueues队列里,并且回调类型callbackType是CALLBACK_TRAVERSAL
            mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);
    
            if (dueTime <= now) {
                // 如果已经到触发时间就立即申请,请求垂直同步信号(申请不表示马上就有,而是等到下一个VSync下来的时候)
                scheduleFrameLocked(now);
            } else {
                // 向Handler发送一个消息,指定的时间执行,并且是异步消息
                Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
                msg.arg1 = callbackType;
                msg.setAsynchronous(true);
                mHandler.sendMessageAtTime(msg, dueTime);
            }
        }
    }
    
    // scheduleFrameLocked里最终通过scheduleVsyncLocked,向系统申请,请求垂直同步信号
    private void scheduleVsyncLocked() {
        // mDisplayEventReceiver是内部类FrameDisplayEventReceiver
        mDisplayEventReceiver.scheduleVsync();
    }
    
    // 内部类FrameDisplayEventReceiver
    private final class FrameDisplayEventReceiver extends DisplayEventReceiver
            implements Runnable {
        private boolean mHavePendingVsync;
        private long mTimestampNanos;
        private int mFrame;
    
        public FrameDisplayEventReceiver(Looper looper, int vsyncSource) {
            super(looper, vsyncSource);
        }
        
        @Override
        public void onVsync(long timestampNanos, int builtInDisplayId, int frame) {
            // 当VSYNC垂直同步下来时,会回调改方法
            long now = System.nanoTime();
            mTimestampNanos = timestampNanos;
            mFrame = frame;
            // 向Handler发送消息,时间一到则执行run方法,即下面重写的run
            Message msg = Message.obtain(mHandler, this);
            msg.setAsynchronous(true);
            mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);
        }
    
        @Override
        public void run() {
            mHavePendingVsync = false;
            doFrame(mTimestampNanos, mFrame);
        }
    }
    
    void doFrame(long frameTimeNanos, int frame) {
        final long startNanos;
        synchronized (mLock) {
            if (!mFrameScheduled) {
                return; // no work to do
            }
    
            long intendedFrameTimeNanos = frameTimeNanos;
            startNanos = System.nanoTime();
            final long jitterNanos = startNanos - frameTimeNanos;
            if (jitterNanos >= mFrameIntervalNanos) {
                final long skippedFrames = jitterNanos / mFrameIntervalNanos;
                final long lastFrameOffset = jitterNanos % mFrameIntervalNanos;
                frameTimeNanos = startNanos - lastFrameOffset;
            }
            // 垂直同步时间上一次时间还小,就安排下次垂直同步,直接返回
            if (frameTimeNanos < mLastFrameTimeNanos) {
                scheduleVsyncLocked();
                return;
            }
    
            if (mFPSDivisor > 1) {
                long timeSinceVsync = frameTimeNanos - mLastFrameTimeNanos;
                if (timeSinceVsync < (mFrameIntervalNanos * mFPSDivisor) && timeSinceVsync > 0) {
                    scheduleVsyncLocked();
                    return;
                }
            }
    
            mFrameInfo.setVsync(intendedFrameTimeNanos, frameTimeNanos);
            mFrameScheduled = false;
            mLastFrameTimeNanos = frameTimeNanos;
        }
    
        try {
            Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Choreographer#doFrame");
            AnimationUtils.lockAnimationClock(frameTimeNanos / TimeUtils.NANOS_PER_MS);
    
            mFrameInfo.markInputHandlingStart();
            // 执行回调,最终就是从CallbackQueues队列里,拿出对应类型的callBackType,执行其run方法,也就是
            // mChoreographer.postCallback带进来的Runnable
            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 {
            AnimationUtils.unlockAnimationClock();
            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
        }
    }
    
    // ViewRootImpl类
    final class TraversalRunnable implements Runnable {
        @Override
        public void run() {
            doTraversal();
        }
    }
    
    // ViewRootImpl类
    void doTraversal() {
        if (mTraversalScheduled) {
            mTraversalScheduled = false;
            // 移除同步屏障信号
            mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
            // 执行measure、layout、draw
            performTraversals();
        }
    }
    

    同步消息屏障

    void scheduleTraversals() {
        if (!mTraversalScheduled) {
            mTraversalScheduled = true;
            // 往MainLooper里发送一个同步消息屏障信号
            mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
        }
    }
    

    我们知道,Android是基于消息机制的,每一个操作都是一个Message,如果在触发绘制的时候,消息队列中还有很多消息没有被执行,那是不是意味着要等到消息队列中的消息执行完成后,绘制消息才能被执行到,那么依然无法保证Vsync信号和绘制的同步,所以依然可能出现丢帧的现象
    还记不记得我们之前在Choreographer#scheduleFrameLocked()和FrameDisplayEventReceiver#onVsync()中提到,我们会给与Message有关的绘制请求设置成异步消息(msg.setAsynchronous(true)),为什么要这么做呢?这时候MessageQueue#postSyncBarrier()就发挥它的作用了,简单来说,它的作用就是一个同步消息屏障,能够把我们的异步消息(也就是绘制消息)的优先级提到最高。

    主线程的 Looper 会一直循环调用 MessageQueue 的 next() 来取出队头的 Message 执行,当 Message 执行完后再去取下一个。当 next() 方法在取 Message 时发现队头是一个同步屏障的消息时,就会去遍历整个队列,只寻找设置了异步标志的消息,如果有找到异步消息,那么就取出这个异步消息来执行,否则就让 next() 方法陷入阻塞状态。如果 next() 方法陷入阻塞状态,那么主线程此时就是处于空闲状态的,也就是没在干任何事。所以,如果队头是一个同步屏障的消息的话,那么在它后面的所有同步消息就都被拦截住了,直到这个同步屏障消息被移除,否则主线程就一直不会去处理同步屏障后面的同步消息
    那这么同步屏障是什么时候被移除的呢?
    其实我们就是在我们上面提到的ViewRootImp#doTraversal()方法中

    void doTraversal() {
        if (mTraversalScheduled) {
            mTraversalScheduled = false;
            // 移除同步消息屏障信号
            mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
            // 执行measure、layout、draw
            performTraversals();
        }
    }
    

    整体流程图
    在这里插入图片描述

    Q&A
    Q1:这个 16.6ms 刷新一次屏幕到底是什么意思呢?是指每隔 16.6ms 调用 onDraw() 绘制一次么?
    A1:不是,16.6ms一次VSYNC信号的同步,但不一定每次都回去绘制,先要应用端发起绘制,向SurfaceFlinger注册后,当垂直同步信号到来,才会发起绘制。

    Q2:如果界面一直保持没变的话,那么还会每隔 16.6ms 刷新一次屏幕么?
    A2:界面没有重绘,应用就不会收的vsync信号,CPU没有向GPU提交数据,但屏幕还是会刷新,依旧会隔16.6ms读取缓冲区数据,只是数据还是旧的,所以看起来没什么变化而已

    Q3:界面的显示其实就是一个 Activity 的 View 树里所有的 View 都进行测量、布局、绘制操作之后的结果呈现,那么如果这部分工作都完成后,屏幕会马上就刷新么?
    A3:不会

    Q4:网上都说避免丢帧的方法之一是保证每次绘制界面的操作要在 16.6ms 内完成,但如果这个 16.6ms 是一个固定的频率的话,请求绘制的操作在代码里被调用的时机是不确定的啊,那么如果某次用户点击屏幕导致的界面刷新操作是在某一个 16.6ms 帧快结束的时候,那么即使这次绘制操作小于 16.6 ms,按道理不也会造成丢帧么?这又该如何理解?
    A4:重绘不是马上开始,是在下一次垂直同步信号到来的时候,才进行绘制

    Q5:大伙都清楚,主线程耗时的操作会导致丢帧,但是耗时的操作为什么会导致丢帧?它是如何导致丢帧发生的
    A5:造成丢帧大体上有两类原因,一是遍历绘制 View 树计算屏幕数据的时间超过了 16.6ms;二是,主线程一直在处理其他耗时的消息,导致遍历绘制 View 树的工作迟迟不能开始,从而超过了 16.6 ms 底层切换下一帧画面的时机。

    展开全文
  • 想把Android手机的帧率降低,使用adb应该如何操作啊?
  • 文章目录一、相关知识科普:二、...Android刷新频率是60帧/秒,Android系统中每隔16.6ms会发送一次VSYNC(同步)信号,有可能会触发UI的渲染 二、流程: (1)界面上任何一个View的刷新请求最终都会走到ViewRoot
  • 本文禁止转载,如有需求,请联系作者。 什么是屏幕刷新率,什么是应用显示帧率。 如何修改LCD的刷新率。 Android的显示刷新率切换策略。
  • 3188LCDC刷新率修改

    2014-09-18 11:08:15
    3188SDK高清屏LCDC刷新率优化修改说明
  • 视频帧率与显示刷新率

    千次阅读 2021-04-28 23:16:47
    固定帧率视频 固定帧率视频每帧的时长是固定长度的。 可变帧率视频 可变帧率的视频,每帧的视频时长不一定...视频帧率和屏幕刷新率不匹配时,会使用Pull_Down技术,24-60的匹配就是3:2 Pull_Down。 电视如何播放24fps
  • Android 显示刷新频率

    千次阅读 2021-08-02 22:39:20
    Android 显示刷新频率 开发者选项->显示刷新频率 packages/apps/Settings/src/com/android/settings/development/ShowRefreshRatePreferenceController.java 调用 SurfaceFlinger::onTransact 中 1034 方法 ...
  • --- a/kernel-3.18/drivers/misc/mediatek/lcm/px080ij21110717a_wuxga_dsi_vdo/px080ij21110717a_wuxga_dsi_vdo.c+++ b/kernel-3.18/drivers/misc/mediatek/lcm/px080ij21110717a_wuxga_dsi_vdo/px080ij21110717a_w...
  • Android 开发过程中,我们经常谈到布局优化、卡顿优化时,通常都知道要减少布局层级、避免主线程做耗时操作等等,这样可以减少丢帧,如果丢帧...这篇文章我们来详细分析 Android 屏幕刷新机制,便于优化我们的项目。
  • java源码屏幕刷新安卓 突围 v1.0.2 (这以前托管在 上。) 这是经典破砖游戏的 Android 实现。 这主要用作示例代码,提供一个简单但完整游戏的示例。 它将在 Froyo (API 8) 及更高版本上运行。 您会在来源中找到一些...
  • iQOO Z1智能手机 - 对比红米K30iQOO Z1智能手机 - 搭配飞智wee 2T手柄iQOO Z1是一款主打游戏娱乐和性价比的机器,虽然在大家的印象中一款“电竞手机”配置联发科的处理器总觉得有些不...144Hz高刷新率屏也是这款手机...
  • 我正在尝试提高我的Beacon App...我读到 Android Beacon Library 的默认刷新率设置为1100ms,这似乎是这种情况 .但似乎我无法改变这个刷新率(Android信标库) . 我试过了:@Overridepublic void onBeaconServiceConne...
  • 获取和设置屏幕刷新频率 获取和设置屏幕刷新频率 获取和设置屏幕刷新频率
  • android 获取手机屏幕刷新频率

    万次阅读 2017-05-22 16:10:31
    Display display = getWindowManager().getDefaultDisplay(); float refreshRate = display.getRefreshRate();
  • 1、刷新频率、 2、单缓冲、双缓冲、三缓冲,掉帧 3、编舞者 源码 4、异步消息、同步屏障 背景 当我们谈到 布局优化 时,通常都知道 需要减少布局层级。那么较多层级的布局是如何影响布局展示的呢?类似的,页面卡顿...
  • 深入理解Android屏幕刷新机制与View三大流程关系 博客仅作为个人学习使用,不定期更新,方便以后复习时能够快速拾回这段遗忘的知识。如果有读者无意搜索到这篇文章,阅读后觉得对你有所帮助,希望您能点个赞,感谢...
  • 这篇文章我们来理解下屏幕刷新机制,先提出几个问题,大家可以带着问题去阅读这篇文章 丢帧一般是什么原因引起的? Android刷新频率60帧/秒,每隔16ms调onDraw绘制一次? onDraw完之后屏幕会马上刷新吗? 如果界面...
  • 一、什么是屏幕刷新机制 屏幕的刷新包括三个步骤: CPU 计算屏幕数据 GPU 进一步处理和缓存 Display 将缓存中(buffer)的屏幕数据显示出来。 屏幕刷新机制包含以下几点要素,需要我们了解和掌握: View 发起...
  • Android屏幕刷新——源码分析

    千次阅读 2020-07-11 17:45:18
    Android屏幕刷新原理——源码分析 文章目录Android屏幕刷新原理——源码分析概述VSync信号三级缓冲源码分析消息队列的同步屏障参考资料 概述 Android系统每16ms(一般的安卓手机的FPS(每秒的帧数)是60)会请求一次...
  • ProMotion 是 iOS 在支持 120hz 之后出现的动态刷新率支持,也就是不同场景使用不同的屏幕刷新率,从而实现体验上提升的同时降低了电池的消耗。 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接...
  • Android 屏幕刷新机制

    千次阅读 2022-03-01 11:34:25
    Android 4.1 Jelly Bean 推出了 Project Butter 用于解决 Android 系统一直以来的 UI 流畅性问题。引入了三个核心元素,即VSYNC、Triple Buffer和Choreographer。其中,VSYNC是理解Project Buffer的核心。VSYNC是...
  • Android中,当我们谈到 布局优化、卡顿优化 时,通常都知道 需要减少布局层级、减少主线程耗时操作,这样可以减少丢帧。如果丢帧比较严重,那么界面可能会有明显的卡顿感。我们知道 通常手机刷新是每秒60次,即每...
  • 本文介绍了Android系统屏幕刷新规则 渲染性能出现的原因 以及解决问题可以使用的工具
  • Android测试刷新率源代码

    热门讨论 2010-06-10 11:14:21
    简单测试 android系统屏幕刷新率 学习用途
  • Android 的 UI 渲染性能是 Google 工程师们长期以来非常重视的,随着 Android 系统的不断演进和完善,Google 在 2012 年的 I/O 大会上宣布 Project Butter 计划,并在 Android 4.1 中正式开始实施,以优化 UI 渲染...
  • 刷新率(Refresh Rate):代表了屏幕在一秒内刷新屏幕的次数,这取决于硬件的固定参数,例如 60Hz。 帧率(Frame Rate):代表了 GPU 在一秒内绘制操作的帧数,例如 30fps,60fps。 GPU 会获取图形数据进行渲染,...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 8,276
精华内容 3,310
关键字:

android 屏幕刷新率