当前位置:首页>> Android深入浅出之Surface探讨

Android深入浅出之Surface探讨

发布时间:2016-03-27作者:智汇小新

  一 目的

  本节的目的就是为了讲清楚Android中的Surface系统,大家耳熟能详的SurfaceFlinger到底是个什么东西,它的工作流程又是怎样的。当然,鉴于SurfaceFlinger的复杂性,我们依然将采用情景分析的办法,找到合适的切入点。

  一个Activity是怎么在屏幕上显示出来的呢?我将首先把这个说清楚。

  接着我们把其中的关键调用抽象在Native层,以这些函数调用为切入点来研究SurfaceFlinger。好了,开始我们的征途吧。

  二 Activity是如何显示的

  最初的想法就是,Activity获得一块显存,然后在上面绘图,最后交给设备去显示。这个道理是没错,但是Android的SurfaceFlinger是在System Server进程中创建的,Activity一般另有线程,这之间是如何。..如何挂上关系的呢?我可以先提前告诉大家,这个过程还比较复杂。呵呵。

  好吧,我们从Activity最初的启动开始。代码在

  framework/base/core/java/android/app/ActivityThread.java中,这里有个函数叫handleLaunchActivity

  [----》ActivityThread:: handleLaunchActivity()]

  private final void handleLaunchActivity(ActivityRecord r, Intent customIntent) {

  Activity a = performLaunchActivity(r, customIntent);

  if (a != null) {

  r.createdConfig = new Configuration(mConfiguration);

  Bundle oldState = r.state;

  handleResumeActivity(r.token, false, r.isForward);

  ----》调用handleResumeActivity

  }

  handleLaunchActivity中会调用handleResumeActivity。

  [---》ActivityThread:: handleResumeActivity]

  final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward) {

  boolean willBeVisible = !a.mStartedActivity;

  if (r.window == null && !a.mFinished && willBeVisible) {

  r.window = r.activity.getWindow();

  View decor = r.window.getDecorView();

  decor.setVisibility(View.INVISIBLE);

  ViewManager wm = a.getWindowManager();

  WindowManager.LayoutParams l = r.window.getAttributes();

  a.mDecor = decor;

  l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;

  if (a.mVisibleFromClient) {

  a.mWindowAdded = true;

  wm.addView(decor, l); //这个很关键。

  }

 

  上面addView那几行非常关键,它关系到咱们在Activity中setContentView后,整个Window到底都包含了些什么。我先告诉大家。所有你创建的View之上,还有一个DecorView,这是一个FrameLayout,另外还有一个PhoneWindow。上面这些东西的代码在

  framework/Policies/Base/Phone/com/android/Internal/policy/impl。这些隐藏的View的创建都是由你在Acitivty的onCreate中调用setContentView导致的。

  [----》PhoneWindow:: addContentView]

  public void addContentView(View view, ViewGroup.LayoutParams params) {

  if (mContentParent == null) { //刚创建的时候mContentParent为空

  installDecor();

  }

  mContentParent.addView(view, params);

  final Callback cb = getCallback();

  if (cb != null) {

  cb.onContentChanged();

  }

  }

  installDecor将创建mDecor和mContentParent。mDecor是DecorView类型,

  mContentParent是ViewGroup类型

  private void installDecor() {

  if (mDecor == null) {

  mDecor = generateDecor();

  mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);

  mDecor.setIsRootNamespace(true);

  }

  if (mContentParent == null) {

  mContentParent = generateLayout(mDecor);

  那么,ViewManager wm = a.getWindowManager()又返回什么呢?

  PhoneWindow从Window中派生,Acitivity创建的时候会调用它的setWindowManager。而这个函数由Window类实现。

  代码在framework/base/core/java/android/view/Window.java中

  public void setWindowManager(WindowManager wm,IBinder appToken, String appName) {

  mAppToken = appToken;

  mAppName = appName;

  if (wm == null) {

  wm = WindowManagerImpl.getDefault();

  }

  mWindowManager = new LocalWindowManager(wm);

  }

  你看见没,分析JAVA代码这个东西真的很复杂。mWindowManager的实现是LocalWindowManager,但由通过Bridge模式把功能交给WindowManagerImpl去实现了。

  真的很复杂!

  好了,罗里罗嗦的,我们回到wm.addView(decor, l)。最终会由WindowManagerImpl来完成

  addView操作,我们直接看它的实现好了。

  代码在framework/base/core/java/android/view/WindowManagerImpl.java

  [----》addView]

  private void addView(View view, ViewGroup.LayoutParams params, boolean nest)

  {

  ViewRoot root; //ViewRoot,我们的主人公终于登场!

  synchronized (this) {

  root = new ViewRoot(view.getContext());

  root.mAddNesting = 1;

  view.setLayoutParams(wparams);

  if (mViews == null) {

  index = 1;

  mViews = new View[1];

  mRoots = new ViewRoot[1];

  mParams = new WindowManager.LayoutParams[1];

  } else {

  }

  index--;

  mViews[index] = view;

  mRoots[index] = root;

  mParams[index] = wparams;

  }

  root.setView(view, wparams, panelParentView);

  }

 

  ViewRoot是整个显示系统中最为关键的东西,看起来这个东西好像和View有那么点关系,其实它根本和View等UI关系不大,它不过是一个Handler罢了,唯一有关系的就是它其中有一个变量为Surface类型。我们看看它的定义。ViewRoot代码在

  framework/base/core/java/android/view/ViewRoot.java中

  public final class ViewRoot extends Handler implements ViewParent,

  View.AttachInfo.Callbacks

  {

  private final Surface mSurface = new Surface();

  }

  它竟然从handler派生,而ViewParent不过定义了一些接口函数罢了。

  看到Surface直觉上感到它和SurfaceFlinger有点关系。要不先去看看?

  Surface代码在framework/base/core/java/android/view/Surface.java中,我们调用的是无参构造函数。

  public Surface() {

  mCanvas = new CompatibleCanvas(); //就是创建一个Canvas!

  }

  如果你有兴趣的话,看看Surface其他构造函数,最终都会调用native的实现,而这些native的实现将和SurfaceFlinger建立关系,但我们这里ViewRoot中的mSurface显然还没有到这一步。那它到底是怎么和SurfaceFlinger搞上的呢?这一切待会就会水落石出的。

  另外,为什么ViewRoot是主人公呢?因为ViewRoot建立了客户端和SystemServer的关系。我们看看它的构造函数。

  public ViewRoot(Context context) {

  super();

  。..。

  getWindowSession(context.getMainLooper());

  }

  getWindowsession将建立和WindowManagerService的关系。

  ublic static IWindowSession getWindowSession(Looper mainLooper) {

  synchronized (mStaticInit) {

  if (!mInitialized) {

  try {

  //sWindowSession是通过Binder机制创建的。终于让我们看到点希望了

  InputMethodManager imm = InputMethodManager.getInstance(mainLooper);

  sWindowSession = IWindowManager.Stub.asInterface(

  ServiceManager.getService(“window”))

  .openSession(imm.getClient(), imm.getInputContext());

  mInitialized = true;

  } catch (RemoteException e) {

  }

  }

  return sWindowSession;

  }

  }

  上面跨Binder的进程调用另一端是WindowManagerService,代码在

  framework/base/services/java/com/android/server/WindowManagerService.java中。我们先不说这个。

  回过头来看看ViewRoot接下来的调用。

  [--》ViewRoot::setView()],这个函数很复杂,我们看其中关键几句。

  public void setView(View view, WindowManager.LayoutParams attrs,

  View panelParentView) {

  synchronized (this) {

  requestLayout();

  try {

  res = sWindowSession.add(mWindow, mWindowAttributes,

  getHostVisibility(), mAttachInfo.mContentInsets);

  }

  }

  requestLayout实现很简单,就是往handler中发送了一个消息。

  public void requestLayout() {

  checkThread();

  mLayoutRequested = true;

  scheduleTraversals(); //发送DO_TRAVERSAL消息

  }

  public void scheduleTraversals() {

  if (!mTraversalScheduled) {

  mTraversalScheduled = true;

  sendEmptyMessage(DO_TRAVERSAL);

  }

  }

 

  我们看看跨进程的那个调用。sWindowSession.add。它的最终实现在WindowManagerService中。

  [---》WindowSession::add()]

  public int add(IWindow window, WindowManager.LayoutParams attrs,

  int viewVisibility, Rect outContentInsets) {

  return addWindow(this, window, attrs, viewVisibility, outContentInsets);

  }

  WindowSession是个内部类,会调用外部类的addWindow

  这个函数巨复杂无比,但是我们的核心目标是找到创建显示相关的部分。所以,最后精简的话就简单了。

  [---》WindowManagerService:: addWindow]

  public int addWindow(Session session, IWindow client,

  WindowManager.LayoutParams attrs, int viewVisibility,

  Rect outContentInsets) {

  //创建一个WindowState,这个又是什么玩意儿呢?

  win = new WindowState(session, client, token,

  attachedWindow, attrs, viewVisibility);

  win.attach();

  return res;

  }

  WindowState类中有一个和Surface相关的成员变量,叫SurfaceSession。它会在

  attach函数中被创建。SurfaceSession嘛,就和SurfaceFlinger有关系了。我们待会看。

  好,我们知道ViewRoot创建及调用add后,我们客户端的View系统就和WindowManagerService建立了牢不可破的关系。

  另外,我们知道ViewRoot是一个handler,而且刚才我们调用了requestLayout,所以接下来消息循环下一个将调用的就是ViewRoot的handleMessage。

  public void handleMessage(Message msg) {

  switch (msg.what) {

  case DO_TRAVERSAL:

  performTraversals();

  performTraversals更加复杂无比,经过我仔细挑选,目标锁定为下面几个函数。当然,后面我们还会回到performTraversals,不过我们现在更感兴趣的是Surface是如何创建的。

  private void performTraversals() {

  // cache mView since it is used so much below.。.

  final View host = mView;

  boolean initialized = false;

  boolean contentInsetsChanged = false;

  boolean visibleInsetsChanged;

  try {

  //ViewRoot也有一个Surface成员变量,叫mSurface,这个就是代表SurfaceFlinger的客户端

  //ViewRoot在这个Surface上作画,最后将由SurfaceFlinger来合成显示。刚才说了mSurface还没有什么内容。

  relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);

  [----》ViewRoot:: relayoutWindow()]

  private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,

  boolean insetsPending) throws RemoteException {

  //relayOut是跨进程调用,mSurface做为参数传进去了,看来离真相越来越近了呀!

  int relayoutResult = sWindowSession.relayout(

  mWindow, params,

  (int) (mView.mMeasuredWidth * appScale + 0.5f),

  (int) (mView.mMeasuredHeight * appScale + 0.5f),

  viewVisibility, insetsPending, mWinFrame,

  mPendingContentInsets, mPendingVisibleInsets,

  mPendingConfiguration, mSurface); mSurface做为参数传进去了。

  }

  我们赶紧转到WindowManagerService去看看吧。、

  public int relayoutWindow(Session session, IWindow client,

  WindowManager.LayoutParams attrs, int requestedWidth,

  int requestedHeight, int viewVisibility, boolean insetsPending,

  Rect outFrame, Rect outContentInsets, Rect outVisibleInsets,

  Configuration outConfig, Surface outSurface){

  。..。.

  try {

  //看到这里,我内心一阵狂喜,有戏,太有戏了!

  //其中win是我们最初创建的WindowState!

  Surface surface = win.createSurfaceLocked();

  if (surface != null) {

  //先创建一个本地surface,然后把传入的参数outSurface copyFrom一下

  outSurface.copyFrom(surface);

  win.mReportDestroySurface = false;

  win.mSurfacePendingDestroy = false;

  } else {

  outSurface.release();

  }

  }

  }

  [---》WindowState::createSurfaceLocked]

  Surface createSurfaceLocked() {

  try {

  mSurface = new Surface(

  mSession.mSurfaceSession, mSession.mPid,

  mAttrs.getTitle().toString(),

  0, w, h, mAttrs.format, flags);

  }

  Surface.openTransaction();

  这里使用了Surface的另外一个构造函数。

  public Surface(SurfaceSession s,

  int pid, String name, int display, int w, int h, int format, int flags)

  throws OutOfResourcesException {

  mCanvas = new CompatibleCanvas();

  init(s,pid,name,display,w,h,format,flags); ----》调用了native的init函数。

  mName = name;

  }

  到这里,不进入JNI是不可能说清楚了。不过我们要先回顾下之前的关键步骤。

 

  l add中,new了一个SurfaceSession

  l 创建new了一个Surface

  l 调用copyFrom,把本地Surface信息传到outSurface中

  JNI层

  上面两个类的JNI实现都在framework/base/core/jni/android_view_Surface.cpp中。

  [----》SurfaceSession:: SurfaceSession()]

  public class SurfaceSession {

  /** Create a new connection with the surface flinger. */

  public SurfaceSession() {

  init();

  }

  它的init函数对应为:

  [---》SurfaceSession_init]

  static void SurfaceSession_init(JNIEnv* env, jobject clazz)

  {

  //SurfaceSession对应为SurfaceComposerClient

  sp《SurfaceComposerClient》 client = new SurfaceComposerClient;

  client-》incStrong(clazz);

  //Google常用做法,在JAVA对象中保存C++对象的指针。

  env-》SetIntField(clazz, sso.client, (int)client.get());

  }

  Surface的init对应为:

  [---》Surface_init]

  static void Surface_init(

  JNIEnv* env, jobject clazz,

  jobject session,

  jint pid, jstring jname, jint dpy, jint w, jint h, jint format, jint flags)

  {

  SurfaceComposerClient* client =

  (SurfaceComposerClient*)env-》GetIntField(session, sso.client);

  sp《SurfaceControl》 surface;

  if (jname == NULL) {

  //client是SurfaceComposerClient,返回的surface是一个SurfaceControl

  //真得很复杂!

  surface = client-》createSurface(pid, dpy, w, h, format, flags);

  } else {

  const jchar* str = env-》GetStringCritical(jname, 0);

  const String8 name(str, env-》GetStringLength(jname));

  env-》ReleaseStringCritical(jname, str);

  surface = client-》createSurface(pid, name, dpy, w, h, format, flags);

  }

  //把surfaceControl信息设置到Surface对象中

  setSurfaceControl(env, clazz, surface);

  }

  static void setSurfaceControl(JNIEnv* env, jobject clazz,

  const sp《SurfaceControl》& surface)

  {

  SurfaceControl* const p =

  (SurfaceControl*)env-》GetIntField(clazz, so.surfaceControl);

  if (surface.get()) {

  surface-》incStrong(clazz);

  }

  if (p) {

  p-》decStrong(clazz);

  }

  env-》SetIntField(clazz, so.surfaceControl, (int)surface.get());

  }

  [---》Surface_copyFrom]

  static void Surface_copyFrom(

  JNIEnv* env, jobject clazz, jobject other)

  {

  const sp《SurfaceControl》& surface = getSurfaceControl(env, clazz);

  const sp《SurfaceControl》& rhs = getSurfaceControl(env, other);

  if (!SurfaceControl::isSameSurface(surface, rhs)) {

  setSurfaceControl(env, clazz, rhs);

  //把本地那个surface的surfaceControl对象转移到outSurface上

  }

  }

  这里仅仅是surfaceControl的转移,但是并没有看到Surface相关的信息。

  那么Surface在哪里创建的呢?为了解释这个问题,我使用了终极武器,aidl。

  1 终极武器AIDL

  aidl可以把XXX.aidl文件转换成对应的java文件。我们刚才调用的是WindowSession的

  relayOut函数。如下:

  sWindowSession.relayout(

  mWindow, params,

  (int) (mView.mMeasuredWidth * appScale + 0.5f),

  (int) (mView.mMeasuredHeight * appScale + 0.5f),

  viewVisibility, insetsPending, mWinFrame,

  mPendingContentInsets, mPendingVisibleInsets,

  mPendingConfiguration, mSurface);

  它的aidl文件在framework/base/core/java/android/view/IWindowSession.aidl中

  interface IWindowSession {

  int add(IWindow window, in WindowManager.LayoutParams attrs,

  in int viewVisibility, out Rect outContentInsets);

  void remove(IWindow window);

  //注意喔,这个outSurface前面的是out,表示输出参数,这个类似于C++的引用。

  int relayout(IWindow window, in WindowManager.LayoutParams attrs,

  int requestedWidth, int requestedHeight, int viewVisibility,

  boolean insetsPending, out Rect outFrame, out Rect outContentInsets,

  out Rect outVisibleInsets, out Configuration outConfig,

  out Surface outSurface);

  刚才说了,JNI及其JAVA调用只是copyFrom了SurfaceControl对象到outSurface中,但是没看到哪里创建Surface。这其中的奥秘就在aidl文件编译后生成的java文件中。

 

  你在命令行下可以输入:

  aidl -Id:\android-2.2-froyo-20100625-source\source\frameworks\base\core\java\ -Id:\android-2.2-froyo-20100625-source\source\frameworks\base\Graphics\java d:\android-2.2-froyo-20100625-source\source\frameworks\base\core\java\android\view\IWindowSession.aidl test.java

  以生成test.java文件。-I参数指定include目录,例如aidl有些参数是在别的java文件中指定的,那么这个-I就需要把这些目录包含进来。

  先看看ViewRoot这个客户端生成的代码是什么。

  public int relayout(

  android.view.IWindow window,

  android.view.WindowManager.LayoutParams attrs,

  int requestedWidth, int requestedHeight,

  int viewVisibility, boolean insetsPending,

  android.graphics.Rect outFrame,

  android.graphics.Rect outContentInsets,

  android.graphics.Rect outVisibleInsets,

  android.content.res.Configuration outConfig,

  android.view.Surface outSurface) ----》outSurface是第11个参数

  throws android.os.RemoteException

  {

  android.os.Parcel _data = android.os.Parcel.obtain();

  android.os.Parcel _reply = android.os.Parcel.obtain();

  int _result;

  try {

  _data.writeInterfaceToken(DESCRIPTOR);

  _data.writeStrongBinder((((window!=null))?(window.asBinder()):(null)));

  if ((attrs!=null)) {

  _data.writeInt(1);

  attrs.writeToParcel(_data, 0);

  }

  else {

  _data.writeInt(0);

  }

  _data.writeInt(requestedWidth);

  _data.writeInt(requestedHeight);

  _data.writeInt(viewVisibility);

  _data.writeInt(((insetsPending)?(1):(0)));

  //奇怪,outSurface的信息没有写到_data中。那。..。.

  mRemote.transact(Stub.TRANSACTION_relayout, _data, _reply, 0);

  _reply.readException();

  _result = _reply.readInt();

  if ((0!=_reply.readInt())) {

  outFrame.readFromParcel(_reply);

  }

  。..。

  if ((0!=_reply.readInt())) {

  outSurface.readFromParcel(_reply); //从Parcel中读取信息来填充outSurface

  }

  }

  finally {

  _reply.recycle();

  _data.recycle();

  }

  return _result;

  }

  真奇怪啊,Binder客户端这头竟然没有把outSurface的信息发过去。我们赶紧看看服务端。

  服务端这边处理是在onTranscat函数中。

  @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException

  {

  switch (code)

  {

  case TRANSACTION_relayout:

  {

  data.enforceInterface(DESCRIPTOR);

  android.view.IWindow _arg0;

  android.view.Surface _arg10;

  //刚才说了,Surface信息并没有传过来,那么我们在relayOut中看到的outSurface是怎么

  //出来的呢?看下面这句,原来在服务端这边竟然new了一个新的Surface!!!

 

  _arg10 = new android.view.Surface();

  int _result = this.relayout(_arg0, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6, _arg7, _arg8, _arg9, _arg10);

  reply.writeNoException();

  reply.writeInt(_result);

  //_arg10是copyFrom了,那怎么传到客户端呢?

  if ((_arg10!=null)) {

  reply.writeInt(1);//调用Surface的writeToParcel,把信息加入reply

  _arg10.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);

  }

  return true;

  }

  太诡异了!竟然有这么多花花肠子。我相信如果没有aidl的帮助,我无论如何也不会知道这其中的奥妙。

  那好,我们的流程明白了。

  l 客户端虽然传了一个surface,但其实没传递给服务端

  l 服务端调用writeToParcel,把信息写到Parcel中,然后数据传回客户端

  l 客户端调用Surface的readFromParcel,获得surface信息。

  那就去看看writeToParcel吧。

  [----》Surface_writeToParcel]

  static void Surface_writeToParcel(

  JNIEnv* env, jobject clazz, jobject argParcel, jint flags)

  {

  Parcel* parcel = (Parcel*)env-》GetIntField(

  argParcel, no.native_parcel);

  const sp《SurfaceControl》& control(getSurfaceControl(env, clazz));

  //还好,只是把数据序列化到Parcel中

  SurfaceControl::writeSurfaceToParcel(control, parcel);

  if (flags & PARCELABLE_WRITE_RETURN_VALUE) {

  setSurfaceControl(env, clazz, 0);

  }

  }

  那看看客户端的Surface_readFromParcel吧。

  [-----》Surface_readFromParcel]

  static void Surface_readFromParcel(

  JNIEnv* env, jobject clazz, jobject argParcel)

  {

  Parcel* parcel = (Parcel*)env-》GetIntField( argParcel, no.native_parcel);

  //客户端这边还没有surface呢

  const sp《Surface》& control(getSurface(env, clazz));

  //不过我们看到希望了,根据服务端那边Parcel信息来构造一个新的surface

  sp《Surface》 rhs = new Surface(*parcel);

  if (!Surface::isSameSurface(control, rhs)) {

  setSurface(env, clazz, rhs); //把这个新surface赋给客户端。终于我们有了surface!

  }

  }

  到此,我们终于七拐八绕的得到了surface,这其中经历太多曲折了。下一节,我们将精简这其中复杂的操作,统一归到Native层,以这样为切入点来了解Surface的工作流程和原理。

  好,反正你知道ViewRoot调用了relayout后,Surface就真正从WindowManagerService那得到了。继续回到ViewRoot,其中还有一个重要地方是我们知道却不了解的。

  private void performTraversals() {

  // cache mView since it is used so much below.。.

  final View host = mView;

  boolean initialized = false;

  boolean contentInsetsChanged = false;

  boolean visibleInsetsChanged;

  try {

  relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);

  // relayoutWindow完后,我们得到了一个无比宝贵的Surface

  //那我们画界面的地方在哪里?就在这个函数中,离relayoutWindow不远处。

  。..。

  boolean cancelDraw = attachInfo.mTreeObserver.dispatchOnPreDraw();

  if (!cancelDraw && !newSurface) {

  mFullRedrawNeeded = false;

  draw(fullRedrawNeeded); //draw?draw什么呀?

  }

  [---》ViewRoot::draw()]

  private void draw(boolean fullRedrawNeeded) {

  Surface surface = mSurface; //嘿嘿,不担心了,surface资源都齐全了

  if (surface == null || !surface.isValid()) {

  return;

  }

  if (mAttachInfo.mViewScrollChanged) {

  mAttachInfo.mViewScrollChanged = false;

  mAttachInfo.mTreeObserver.dispatchOnScrollChanged();

  }

  int yoff;

  final boolean scrolling = mScroller != null && mScroller.computeScrollOffset();

  if (scrolling) {

  yoff = mScroller.getCurrY();

  } else {

  yoff = mScrollY;

  }

  if (mCurScrollY != yoff) {

  mCurScrollY = yoff;

  fullRedrawNeeded = true;

  }

  float appScale = mAttachInfo.mApplicationScale;

  boolean scalingRequired = mAttachInfo.mScalingRequired;

  Rect dirty = mDirty;

  if (mUseGL) { //我们不用OPENGL

  。..

  }

  Canvas canvas;

  try {

  int left = dirty.left;

  int top = dirty.top;

  int right = dirty.right;

  int bottom = dirty.bottom;

  //从Surface中锁定一块区域,这块区域是我们认为的需要重绘的区域

  canvas = surface.lockCanvas(dirty);

  // TODO: Do this in native

  canvas.setDensity(mDensity);

  }

  try {

  if (!dirty.isEmpty() || mIsAnimating) {

  long startTime = 0L;

  try {

  canvas.translate(0, -yoff);

  if (mTranslator != null) {

  mTranslator.translateCanvas(canvas);

  }

  canvas.setScreenDensity(scalingRequired

  ? DisplayMetrics.DENSITY_DEVICE : 0);

  //mView就是之前的decoreView,

  mView.draw(canvas);

  }

  } finally {

  //我们的图画完了,告诉surface释放这块区域

 

  surface.unlockCanvasAndPost(canvas);

  }

  if (scrolling) {

  mFullRedrawNeeded = true;

  scheduleTraversals();

  }

  }

  看起来,这个surface的用法很简单嘛:

  l lockSurface,得到一个画布Canvas

  l 调用View的draw,让他们在这个Canvas上尽情绘图才。另外,这个View会调用所有它的子View来画图,最终会进入到View的onDraw函数中,在这里我们可以做定制化的界面美化工作。当然,如果你想定制化整个系统画图的话,完全可以把performTranvsal看懂,然后再修改。

  l unlockCanvasAndPost,告诉Surface释放这块画布

  当然,这几个重要函数调用干了具体的活。这些重要函数,我们最终会精简到Native层的。

  2 总结

  到这里,你应该知道了一个Activity中,调用setContentView后它如何从系统中获取一块Surface,以及它是如何使用这个Surface的了。不得不说,关于UI这块,Android绝对是够复杂的。

公司简介

宜科(天津)电子有限公司是中国工业自动化的领军企业,于2003年在天津投资成立,销售和服务网络覆盖全国。作为中国本土工业自动化产品的提供商和智能制造解决方案的供应商,宜科在汽车、汽车零部件、工程机械、机器人、食品制药、印刷包装、纺织机械、物流设备、电子制造等诸多领域占据领先地位。宜科为智慧工厂的整体规划实施提供自系统层、控制层、网络层到执行层自上而下的全系列服务,产品及解决方案涵盖但不局限于云平台、MES制造执行系统、工业现场总线、工业以太网、工业无线通讯、机器人及智能设备组成的自动化生产线、自动化电气控制系统集成、智能物流仓储系统等,以实现真正智能化的生产制造,从而带来生产力和生产效率的大幅提升,以及对生产灵活性和生产复杂性的管理能力的大幅提升。多年来,宜科以创新的技术、卓越的解决方案和产品坚持不懈地为中国制造业的发展提供全面支持,并以出众的品质和令人信赖的可靠性、领先的技术成就、不懈的创新追求,在业界独树一帜。帮助中国制造业转型升级,加速智能制造进程,成为中国工业4.0智慧工厂解决方案当之无愧的践行者。

更多详情>>

联系我们

  • 联系人:章清涛
  • 热线:18611695135
  • 电话:
  • 传真:
  • 邮箱:18210150532@139.com

Copyright © 2015 ilinki.net Inc. All rights reserved. 智汇工业版权所有

电话:010-62314658 邮箱:service@ilinki.net

主办单位:智汇万联(北京)信息技术有限公司

京ICP备15030148号-1