免费色播,亚洲国产欧美国产第一区二区三区,毛片看,日本精品在线观看视频,国产成人精品一区二区免费视频,日本黄色免费网站,一级毛片免费

Android深入淺出之Surface探討

來(lái)源:網(wǎng)絡(luò)

點(diǎn)擊:971

A+ A-

所屬頻道:新聞中心

關(guān)鍵詞: Android,Surface

      一 目的

      本節(jié)的目的就是為了講清楚Android中的Surface系統(tǒng),大家耳熟能詳?shù)腟urfaceFlinger到底是個(gè)什么東西,它的工作流程又是怎樣的。當(dāng)然,鑒于SurfaceFlinger的復(fù)雜性,我們依然將采用情景分析的辦法,找到合適的切入點(diǎn)。

      一個(gè)Activity是怎么在屏幕上顯示出來(lái)的呢?我將首先把這個(gè)說(shuō)清楚。

      接著我們把其中的關(guān)鍵調(diào)用抽象在Native層,以這些函數(shù)調(diào)用為切入點(diǎn)來(lái)研究SurfaceFlinger。好了,開始我們的征途吧。

      二 Activity是如何顯示的

      最初的想法就是,Activity獲得一塊顯存,然后在上面繪圖,最后交給設(shè)備去顯示。這個(gè)道理是沒錯(cuò),但是Android的SurfaceFlinger是在System Server進(jìn)程中創(chuàng)建的,Activity一般另有線程,這之間是如何。..如何掛上關(guān)系的呢?我可以先提前告訴大家,這個(gè)過(guò)程還比較復(fù)雜。呵呵。

      好吧,我們從Activity最初的啟動(dòng)開始。代碼在

      framework/base/core/java/android/app/ActivityThread.java中,這里有個(gè)函數(shù)叫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);

      ----》調(diào)用handleResumeActivity

      }

      handleLaunchActivity中會(huì)調(diào)用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); //這個(gè)很關(guān)鍵。

      }

     

      上面addView那幾行非常關(guān)鍵,它關(guān)系到咱們?cè)贏ctivity中setContentView后,整個(gè)Window到底都包含了些什么。我先告訴大家。所有你創(chuàng)建的View之上,還有一個(gè)DecorView,這是一個(gè)FrameLayout,另外還有一個(gè)PhoneWindow。上面這些東西的代碼在

      framework/Policies/Base/Phone/com/android/Internal/policy/impl。這些隱藏的View的創(chuàng)建都是由你在Acitivty的onCreate中調(diào)用setContentView導(dǎo)致的。

     ?。?---》PhoneWindow:: addContentView]

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

      if (mContentParent == null) { //剛創(chuàng)建的時(shí)候mContentParent為空

      installDecor();

      }

      mContentParent.addView(view, params);

      final Callback cb = getCallback();

      if (cb != null) {

      cb.onContentChanged();

      }

      }

      installDecor將創(chuàng)建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創(chuàng)建的時(shí)候會(huì)調(diào)用它的setWindowManager。而這個(gè)函數(shù)由Window類實(shí)現(xiàn)。

      代碼在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代碼這個(gè)東西真的很復(fù)雜。mWindowManager的實(shí)現(xiàn)是LocalWindowManager,但由通過(guò)Bridge模式把功能交給WindowManagerImpl去實(shí)現(xiàn)了。

      真的很復(fù)雜!

      好了,羅里羅嗦的,我們回到wm.addView(decor, l)。最終會(huì)由WindowManagerImpl來(lái)完成

      addView操作,我們直接看它的實(shí)現(xiàn)好了。

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

     ?。?---》addView]

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

      {

      ViewRoot root; //ViewRoot,我們的主人公終于登場(chǎng)!

      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是整個(gè)顯示系統(tǒng)中最為關(guān)鍵的東西,看起來(lái)這個(gè)東西好像和View有那么點(diǎn)關(guān)系,其實(shí)它根本和View等UI關(guān)系不大,它不過(guò)是一個(gè)Handler罷了,唯一有關(guān)系的就是它其中有一個(gè)變量為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不過(guò)定義了一些接口函數(shù)罷了。

      看到Surface直覺上感到它和SurfaceFlinger有點(diǎn)關(guān)系。要不先去看看?

      Surface代碼在framework/base/core/java/android/view/Surface.java中,我們調(diào)用的是無(wú)參構(gòu)造函數(shù)。

      public Surface() {

      mCanvas = new CompatibleCanvas(); //就是創(chuàng)建一個(gè)Canvas!

      }

      如果你有興趣的話,看看Surface其他構(gòu)造函數(shù),最終都會(huì)調(diào)用native的實(shí)現(xiàn),而這些native的實(shí)現(xiàn)將和SurfaceFlinger建立關(guān)系,但我們這里ViewRoot中的mSurface顯然還沒有到這一步。那它到底是怎么和SurfaceFlinger搞上的呢?這一切待會(huì)就會(huì)水落石出的。

      另外,為什么ViewRoot是主人公呢?因?yàn)閂iewRoot建立了客戶端和SystemServer的關(guān)系。我們看看它的構(gòu)造函數(shù)。

      public ViewRoot(Context context) {

      super();

      。..。

      getWindowSession(context.getMainLooper());

      }

      getWindowsession將建立和WindowManagerService的關(guān)系。

      ublic static IWindowSession getWindowSession(Looper mainLooper) {

      synchronized (mStaticInit) {

      if (!mInitialized) {

      try {

      //sWindowSession是通過(guò)Binder機(jī)制創(chuàng)建的。終于讓我們看到點(diǎn)希望了

      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的進(jìn)程調(diào)用另一端是WindowManagerService,代碼在

      framework/base/services/java/com/android/server/WindowManagerService.java中。我們先不說(shuō)這個(gè)。

      回過(guò)頭來(lái)看看ViewRoot接下來(lái)的調(diào)用。

     ?。?-》ViewRoot::setView()],這個(gè)函數(shù)很復(fù)雜,我們看其中關(guān)鍵幾句。

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

      View panelParentView) {

      synchronized (this) {

      requestLayout();

      try {

      res = sWindowSession.add(mWindow, mWindowAttributes,

      getHostVisibility(), mAttachInfo.mContentInsets);

      }

      }

      requestLayout實(shí)現(xiàn)很簡(jiǎn)單,就是往handler中發(fā)送了一個(gè)消息。

      public void requestLayout() {

      checkThread();

      mLayoutRequested = true;

      scheduleTraversals(); //發(fā)送DO_TRAVERSAL消息

      }

      public void scheduleTraversals() {

      if (!mTraversalScheduled) {

      mTraversalScheduled = true;

      sendEmptyMessage(DO_TRAVERSAL);

      }

      }

     

      我們看看跨進(jìn)程的那個(gè)調(diào)用。sWindowSession.add。它的最終實(shí)現(xiàn)在WindowManagerService中。

     ?。?--》WindowSession::add()]

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

      int viewVisibility, Rect outContentInsets) {

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

      }

      WindowSession是個(gè)內(nèi)部類,會(huì)調(diào)用外部類的addWindow

      這個(gè)函數(shù)巨復(fù)雜無(wú)比,但是我們的核心目標(biāo)是找到創(chuàng)建顯示相關(guān)的部分。所以,最后精簡(jiǎn)的話就簡(jiǎn)單了。

      [---》WindowManagerService:: addWindow]

      public int addWindow(Session session, IWindow client,

      WindowManager.LayoutParams attrs, int viewVisibility,

      Rect outContentInsets) {

      //創(chuàng)建一個(gè)WindowState,這個(gè)又是什么玩意兒呢?

      win = new WindowState(session, client, token,

      attachedWindow, attrs, viewVisibility);

      win.attach();

      return res;

      }

      WindowState類中有一個(gè)和Surface相關(guān)的成員變量,叫SurfaceSession。它會(huì)在

      attach函數(shù)中被創(chuàng)建。SurfaceSession嘛,就和SurfaceFlinger有關(guān)系了。我們待會(huì)看。

      好,我們知道ViewRoot創(chuàng)建及調(diào)用add后,我們客戶端的View系統(tǒng)就和WindowManagerService建立了牢不可破的關(guān)系。

      另外,我們知道ViewRoot是一個(gè)handler,而且剛才我們調(diào)用了requestLayout,所以接下來(lái)消息循環(huán)下一個(gè)將調(diào)用的就是ViewRoot的handleMessage。

      public void handleMessage(Message msg) {

      switch (msg.what) {

      case DO_TRAVERSAL:

      performTraversals();

      performTraversals更加復(fù)雜無(wú)比,經(jīng)過(guò)我仔細(xì)挑選,目標(biāo)鎖定為下面幾個(gè)函數(shù)。當(dāng)然,后面我們還會(huì)回到performTraversals,不過(guò)我們現(xiàn)在更感興趣的是Surface是如何創(chuàng)建的。

      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也有一個(gè)Surface成員變量,叫mSurface,這個(gè)就是代表SurfaceFlinger的客戶端

      //ViewRoot在這個(gè)Surface上作畫,最后將由SurfaceFlinger來(lái)合成顯示。剛才說(shuō)了mSurface還沒有什么內(nèi)容。

      relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);

     ?。?---》ViewRoot:: relayoutWindow()]

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

      boolean insetsPending) throws RemoteException {

      //relayOut是跨進(jìn)程調(diào)用,mSurface做為參數(shù)傳進(jìn)去了,看來(lái)離真相越來(lái)越近了呀!

      int relayoutResult = sWindowSession.relayout(

      mWindow, params,

     ?。╥nt) (mView.mMeasuredWidth * appScale + 0.5f),

     ?。╥nt) (mView.mMeasuredHeight * appScale + 0.5f),

      viewVisibility, insetsPending, mWinFrame,

      mPendingContentInsets, mPendingVisibleInsets,

      mPendingConfiguration, mSurface); mSurface做為參數(shù)傳進(jìn)去了。

      }

      我們趕緊轉(zhuǎn)到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 {

      //看到這里,我內(nèi)心一陣狂喜,有戲,太有戲了!

      //其中win是我們最初創(chuàng)建的WindowState!

      Surface surface = win.createSurfaceLocked();

      if (surface != null) {

      //先創(chuàng)建一個(gè)本地surface,然后把傳入的參數(shù)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的另外一個(gè)構(gòu)造函數(shù)。

      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); ----》調(diào)用了native的init函數(shù)。

      mName = name;

      }

      到這里,不進(jìn)入JNI是不可能說(shuō)清楚了。不過(guò)我們要先回顧下之前的關(guān)鍵步驟。

     

      l add中,new了一個(gè)SurfaceSession

      l 創(chuàng)建new了一個(gè)Surface

      l 調(diào)用copyFrom,把本地Surface信息傳到outSurface中

      JNI層

      上面兩個(gè)類的JNI實(shí)現(xiàn)都在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函數(shù)對(duì)應(yīng)為:

     ?。?--》SurfaceSession_init]

      static void SurfaceSession_init(JNIEnv* env, jobject clazz)

      {

      //SurfaceSession對(duì)應(yīng)為SurfaceComposerClient

      sp《SurfaceComposerClient》 client = new SurfaceComposerClient;

      client-》incStrong(clazz);

      //Google常用做法,在JAVA對(duì)象中保存C++對(duì)象的指針。

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

      }

      Surface的init對(duì)應(yīng)為:

     ?。?--》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 =

     ?。⊿urfaceComposerClient*)env-》GetIntField(session, sso.client);

      sp《SurfaceControl》 surface;

      if (jname == NULL) {

      //client是SurfaceComposerClient,返回的surface是一個(gè)SurfaceControl

      //真得很復(fù)雜!

      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信息設(shè)置到Surface對(duì)象中

      setSurfaceControl(env, clazz, surface);

      }

      static void setSurfaceControl(JNIEnv* env, jobject clazz,

      const sp《SurfaceControl》& surface)

      {

      SurfaceControl* const p =

     ?。⊿urfaceControl*)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);

      //把本地那個(gè)surface的surfaceControl對(duì)象轉(zhuǎn)移到outSurface上

      }

      }

      這里僅僅是surfaceControl的轉(zhuǎn)移,但是并沒有看到Surface相關(guān)的信息。

      那么Surface在哪里創(chuàng)建的呢?為了解釋這個(gè)問題,我使用了終極武器,aidl。

      1 終極武器AIDL

      aidl可以把XXX.aidl文件轉(zhuǎn)換成對(duì)應(yīng)的java文件。我們剛才調(diào)用的是WindowSession的

      relayOut函數(shù)。如下:

      sWindowSession.relayout(

      mWindow, params,

     ?。╥nt) (mView.mMeasuredWidth * appScale + 0.5f),

     ?。╥nt) (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);

      //注意喔,這個(gè)outSurface前面的是out,表示輸出參數(shù),這個(gè)類似于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);

      剛才說(shuō)了,JNI及其JAVA調(diào)用只是copyFrom了SurfaceControl對(duì)象到outSurface中,但是沒看到哪里創(chuàng)建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參數(shù)指定include目錄,例如aidl有些參數(shù)是在別的java文件中指定的,那么這個(gè)-I就需要把這些目錄包含進(jìn)來(lái)。

      先看看ViewRoot這個(gè)客戶端生成的代碼是什么。

      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個(gè)參數(shù)

      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中讀取信息來(lái)填充outSurface

      }

      }

      finally {

      _reply.recycle();

      _data.recycle();

      }

      return _result;

      }

      真奇怪啊,Binder客戶端這頭竟然沒有把outSurface的信息發(fā)過(guò)去。我們趕緊看看服務(wù)端。

      服務(wù)端這邊處理是在onTranscat函數(shù)中。

      @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;

      //剛才說(shuō)了,Surface信息并沒有傳過(guò)來(lái),那么我們?cè)趓elayOut中看到的outSurface是怎么

      //出來(lái)的呢?看下面這句,原來(lái)在服務(wù)端這邊竟然new了一個(gè)新的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);//調(diào)用Surface的writeToParcel,把信息加入reply

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

      }

      return true;

      }

      太詭異了!竟然有這么多花花腸子。我相信如果沒有aidl的幫助,我無(wú)論如何也不會(huì)知道這其中的奧妙。

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

      l 客戶端雖然傳了一個(gè)surface,但其實(shí)沒傳遞給服務(wù)端

      l 服務(wù)端調(diào)用writeToParcel,把信息寫到Parcel中,然后數(shù)據(jù)傳回客戶端

      l 客戶端調(diào)用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));

      //還好,只是把數(shù)據(jù)序列化到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));

      //不過(guò)我們看到希望了,根據(jù)服務(wù)端那邊Parcel信息來(lái)構(gòu)造一個(gè)新的surface

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

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

      setSurface(env, clazz, rhs); //把這個(gè)新surface賦給客戶端。終于我們有了surface!

      }

      }

      到此,我們終于七拐八繞的得到了surface,這其中經(jīng)歷太多曲折了。下一節(jié),我們將精簡(jiǎn)這其中復(fù)雜的操作,統(tǒng)一歸到Native層,以這樣為切入點(diǎn)來(lái)了解Surface的工作流程和原理。

      好,反正你知道ViewRoot調(diào)用了relayout后,Surface就真正從WindowManagerService那得到了。繼續(xù)回到ViewRoot,其中還有一個(gè)重要地方是我們知道卻不了解的。

      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完后,我們得到了一個(gè)無(wú)比寶貴的Surface

      //那我們畫界面的地方在哪里?就在這個(gè)函數(shù)中,離relayoutWindow不遠(yuǎn)處。

      。..。

      boolean cancelDraw = attachInfo.mTreeObserver.dispatchOnPreDraw();

      if (!cancelDraw && !newSurface) {

      mFullRedrawNeeded = false;

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

      }

     ?。?--》ViewRoot::draw()]

      private void draw(boolean fullRedrawNeeded) {

      Surface surface = mSurface; //嘿嘿,不擔(dān)心了,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中鎖定一塊區(qū)域,這塊區(qū)域是我們認(rèn)為的需要重繪的區(qū)域

      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釋放這塊區(qū)域

     

      surface.unlockCanvasAndPost(canvas);

      }

      if (scrolling) {

      mFullRedrawNeeded = true;

      scheduleTraversals();

      }

      }

      看起來(lái),這個(gè)surface的用法很簡(jiǎn)單嘛:

      l lockSurface,得到一個(gè)畫布Canvas

      l 調(diào)用View的draw,讓他們?cè)谶@個(gè)Canvas上盡情繪圖才。另外,這個(gè)View會(huì)調(diào)用所有它的子View來(lái)畫圖,最終會(huì)進(jìn)入到View的onDraw函數(shù)中,在這里我們可以做定制化的界面美化工作。當(dāng)然,如果你想定制化整個(gè)系統(tǒng)畫圖的話,完全可以把performTranvsal看懂,然后再修改。

      l unlockCanvasAndPost,告訴Surface釋放這塊畫布

      當(dāng)然,這幾個(gè)重要函數(shù)調(diào)用干了具體的活。這些重要函數(shù),我們最終會(huì)精簡(jiǎn)到Native層的。

      2 總結(jié)

      到這里,你應(yīng)該知道了一個(gè)Activity中,調(diào)用setContentView后它如何從系統(tǒng)中獲取一塊Surface,以及它是如何使用這個(gè)Surface的了。不得不說(shuō),關(guān)于UI這塊,Android絕對(duì)是夠復(fù)雜的。

    (審核編輯: 智匯小新)

    聲明:除特別說(shuō)明之外,新聞內(nèi)容及圖片均來(lái)自網(wǎng)絡(luò)及各大主流媒體。版權(quán)歸原作者所有。如認(rèn)為內(nèi)容侵權(quán),請(qǐng)聯(lián)系我們刪除。