相关文章链接:

1. Android Framework - 学习启动篇
2. 源码阅读分析 - Window底层原理与系统架构

相关源码文件:

/frameworks/base/core/java/android/view/ViewRootImpl.java/frameworks/base/core/java/android/view/Choreographer.java/frameworks/base/core/java/android/view/DisplayEventReceiver.java/frameworks/base/core/jni/android_view_DisplayEventReceiver.cpp/frameworks/native/libs/gui/DisplayEventReceiver.cpp/frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp/frameworks/native/services/surfaceflinger/EventThread.cpp/frameworks/native/libs/gui/BitTube.cpp

1. 梳理概述

在开始阅读文章前,希望大家能认真思考几个问题:

  • 界面卡顿的原理是怎样的?
  • ViewRootImpl 与 SurfaceFlinger 是怎么通信的?
  • invalidate / requestLayout 会不会立马刷新屏幕?
  • SurfaceView / GLSurfaceView 的底层实现原理?

搞 Android 搞了几年,我们对 VSync 信号应该会有一些了解,但是未必真正能理解其具体原理。比如 VSync 信号是从哪里来的?发到哪里去?有什么作用?本文主要讲解发到哪里去,至于从哪里来的大家可以看看之前的内容。

2. 请求 VSync 信号

如果我们的界面需要发生变化,一般都会来到 ViewRootImpl 的 requestLayout 方法,有可能是手动触发的也有可能是被动触发的,在这个方法里面我们会主动去请求接收 VSync 信号,当下一次 VSync 信号的来的时候会主动回掉回来,然后才开始真正的绘制流程。

    @Override    public void requestLayout() {      if (!mHandlingLayoutInLayoutRequest) {        checkThread();        mLayoutRequested = true;        scheduleTraversals();      }    }    void scheduleTraversals() {      if (!mTraversalScheduled) {        mTraversalScheduled = true;        // 插入一条消息屏障        mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();        // post 一个 Callback        mChoreographer.postCallback(Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);      }    }    private void postCallbackDelayedInternal(int callbackType, Object action, Object token, long delayMillis) {      synchronized (mLock) {        ...        if (dueTime <= now) {          scheduleFrameLocked(now);        } else {          ...        }      }    }    private void scheduleFrameLocked(long now) {      if (!mFrameScheduled) {        mFrameScheduled = true;        if (USE_VSYNC) {          // 是否在 Choreographer 的工作线程          if (isRunningOnLooperThreadLocked()) {            scheduleVsyncLocked();          } else {            Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC);            msg.setAsynchronous(true);            mHandler.sendMessageAtFrontOfQueue(msg);          }        } else {          ...        }      }    }    // 请求接收下一次 VSync 信号    private void scheduleVsyncLocked() {      mDisplayEventReceiver.scheduleVsync();    }

由上面的源码可以看出,每一次调用 requestLayout 方法,都会主动调用 scheduleVsync 方法来接收下一次的 VSync 信号。也就是说在下一次 VSync 信号来之前,就算连续调用 n 次的 requestLayout 方法,也并不会触发刷新绘制流程。

3. 接收 VSync 信号

应用 App 请求了要接收下一次的 VSync 信号,那么 SurfaceFlinger 服务怎么把 VSync 信号,发给我们的应用 App ?这个得从 DisplayEventReceiver 的初始化入手,涉及到跨进程通信也涉及到 Native 层源码。

    public DisplayEventReceiver(Looper looper) {      ...      // nativeInit       mReceiverPtr = nativeInit(new WeakReference(this), mMessageQueue);    }    static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak, jobject messageQueueObj) {      sp receiver = new NativeDisplayEventReceiver(env, receiverWeak, messageQueue);      // 初始化方法      status_t status = receiver->initialize();      receiver->incStrong(gDisplayEventReceiverClassInfo.clazz); // retain a reference for the object      return reinterpret_cast(receiver.get());    }    status_t NativeDisplayEventReceiver::initialize() {      // 接收端的 fd 添加到 Looper      int rc = mMessageQueue->getLooper()->addFd(mReceiver.getFd(), 0, Looper::EVENT_INPUT,this, NULL);      return OK;    }    // 跨进程创建一个 mEventConnection 对象    DisplayEventReceiver::DisplayEventReceiver() {      sp sf(ComposerService::getComposerService());      if (sf != NULL) {        mEventConnection = sf->createDisplayEventConnection();        if (mEventConnection != NULL) {            mDataChannel = mEventConnection->getDataChannel();        }      }    }    // 获取接收端的 fd    int DisplayEventReceiver::getFd() const {      if (mDataChannel == NULL)          return NO_INIT;      return mDataChannel->getFd();    }    // VSync 信号来会回调到这个方法    int NativeDisplayEventReceiver::handleEvent(int receiveFd, int events, void* data) {      // Drain all pending events, keep the last vsync.      nsecs_t vsyncTimestamp;      int32_t vsyncDisplayId;      uint32_t vsyncCount;      if (processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount)) {        mWaitingForVsync = false;        dispatchVsync(vsyncTimestamp, vsyncDisplayId, vsyncCount);      }      return 1; // keep the callback    }    void NativeDisplayEventReceiver::dispatchVsync(nsecs_t timestamp, int32_t id, uint32_t count) {      JNIEnv* env = AndroidRuntime::getJNIEnv();      ScopedLocalRef receiverObj(env, jniGetReferent(env, mReceiverWeakGlobal));      if (receiverObj.get()) {        // 回掉到 Java 层的 dispatchVsync 方法        env->CallVoidMethod(receiverObj.get(),                gDisplayEventReceiverClassInfo.dispatchVsync, timestamp, id, count);      }    }    @Override    public void onVsync(long timestampNanos, int builtInDisplayId, int frame) {      // 发消息执行 doFrame 方法,真正开始刷新绘制流程      mTimestampNanos = timestampNanos;      mFrame = frame;      Message msg = Message.obtain(mHandler, this);      msg.setAsynchronous(true);      mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);    }

DisplayEventReceiver 在初始化时会创建与 SurfaceFlinger 的 Connection 连接,当应用 App 主动发起 requestNextVsync 后,SurfaceFlinger 会在下一个 VSync 信号来的时候,主动通知我们的应用 App ,回掉到 Java 层的 onVsync 方法,开始真正的刷新绘制流程。

视频地址:https://pan.baidu.com/s/1tQ7omRNg8BgldnkjdlBPlw 
视频密码:6hlc

更多相关文章

  1. android中GridView关于间距的属性值介绍
  2. Android(安卓)studio 连接数据库小经历遇到的问题以及解决方法(ja
  3. Android(安卓)属性动画简介
  4. 从零开始学习android
  5. 详解 Android(安卓)的 Activity 组件
  6. 详解 Android(安卓)的 Activity 组件
  7. Android中通过Intent 调用图片、视频、音频、录音、拍照
  8. android 关于tts的一些参数
  9. android中SharedPreferences和PreferenceActivity的存取数据

随机推荐

  1. 去重和排序如何操作
  2. C#串口通信的实例教程
  3. 分享关于asp注册代码实例
  4. EasyLoader(简单加载)实例
  5. bootstrap-multiselect 多选实例代码
  6. 详解可选参数和命名参数实例
  7. 分享一个IoC入门教程实例
  8. [转]Composite Keys With WebApi OData
  9. 总结EF通用数据层封装类实例详解
  10. [转]Support Composite Key in ASP.NET W