美文网首页
SystemUI(三)扒一扒WindowManager的addV

SystemUI(三)扒一扒WindowManager的addV

作者: 付十一v | 来源:发表于2020-03-22 22:40 被阅读0次

    从上面两篇SystemUI中发现StatusBar是通过WindowManager的addView()添加在界面上,那么内部Window是如何进行添加的?

    带着疑问,跟踪到WindowManager.addView()方法中,由于WindowManager是一个接口,而实现它的是WindowManagerImpl.java

    public final class WindowManagerImpl implements WindowManager {
        private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
        private final Window mParentWindow;
          ...
          
        @Override
        public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
            applyDefaultToken(params);
            mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
        }
            ...
            
    }
    

    在WindowManagerImpl可以发现,最终进行addView操作的是WindowManagerGlobal这个类,接着跟踪进去,可以发现重头戏在WindowManagerGlobal这个类中,那么接下来就开始理清内部逻辑。

          public void addView(View view, ViewGroup.LayoutParams params,
    279              Display display, Window parentWindow) {
    280          if (view == null) {
    281              throw new IllegalArgumentException("view must not be null");
    282          }
    283          if (display == null) {
    284              throw new IllegalArgumentException("display must not be null");
    285          }
    286          if (!(params instanceof WindowManager.LayoutParams)) {
    287              throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
    288          }
    289  
    290          final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
    291          if (parentWindow != null) {
    292              parentWindow.adjustLayoutParamsForSubWindow(wparams);
    293          } else {
    294              // If there's no parent, then hardware acceleration for this view is
    295              // set from the application's hardware acceleration setting.
    296              final Context context = view.getContext();
    297              if (context != null
    298                      && (context.getApplicationInfo().flags
    299                              & ApplicationInfo.FLAG_HARDWARE_ACCELERATED) != 0) {
    300                  wparams.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
    301              }
    302          }
    303  
    304          ViewRootImpl root;
    305          View panelParentView = null;
    306  
    307          synchronized (mLock) {
    308              // Start watching for system property changes.
    309              if (mSystemPropertyUpdater == null) {
    310                  mSystemPropertyUpdater = new Runnable() {
    311                      @Override public void run() {
    312                          synchronized (mLock) {
    313                              for (int i = mRoots.size() - 1; i >= 0; --i) {
    314                                  mRoots.get(i).loadSystemProperties();
    315                              }
    316                          }
    317                      }
    318                  };
    319                  SystemProperties.addChangeCallback(mSystemPropertyUpdater);
    320              }
    321  
    322              int index = findViewLocked(view, false);
    323              if (index >= 0) {
    324                  if (mDyingViews.contains(view)) {
    325                      // Don't wait for MSG_DIE to make it's way through root's queue.
    326                      mRoots.get(index).doDie();
    327                  } else {
    328                      throw new IllegalStateException("View " + view
    329                              + " has already been added to the window manager.");
    330                  }
    331                  // The previous removeView() had not completed executing. Now it has.
    332              }
    333  
    334              // If this is a panel window, then find the window it is being
    335              // attached to for future reference.
    336              if (wparams.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
    337                      wparams.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
    338                  final int count = mViews.size();
    339                  for (int i = 0; i < count; i++) {
    340                      if (mRoots.get(i).mWindow.asBinder() == wparams.token) {
    341                          panelParentView = mViews.get(i);
    342                      }
    343                  }
    344              }
    345  
    346           ...
    365      }
    

    在最开始280行-300行,对传进来的参数进行检查,view,display为null,params不属于WindomManager.LayoutParams都会抛出异常。另外如果是子Window,那么还需要通过adjustLayoutParamsForSubWindow(wparams)对布局参数进行调整。

    在对参数进行检查后,首先通过findViewLocked查找到当前View的索引,并且判断当前view是否包含在mDyingViews(一个存储待删除的View的List集合)中,如果包含其中,则不等待MSG_DIE消息,直接调用doDie根据获取的索引进行删除。否则抛出异常。

    在336处,如果是papanel window,则遍历所有View,获取papanel window所连接的view。准备工作已经做好,接下来就Window进行添加操作。

                    root = new ViewRootImpl(view.getContext(), display);
    347  
    348              view.setLayoutParams(wparams);
    349  
    350              mViews.add(view);
    351              mRoots.add(root);
    352              mParams.add(wparams);
    353  
    354              // do this last because it fires off messages to start doing things
    355              try {
    356                  root.setView(view, wparams, panelParentView);
    357              } catch (RuntimeException e) {
    358                  // BadTokenException or InvalidDisplayException, clean up.
    359                  if (index >= 0) {
    360                      removeViewLocked(index, true);
    361                  }
    362                  throw e;
    363              }
    364          }
    

    在上述代码的最后,通过ViewRootImpl.setView来更新界面.

    public final class ViewRootImpl implements ViewParent,
              View.AttachInfo.Callbacks, ThreadedRenderer.DrawCallbacks { 
                    ...
             public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
                        ...
                try {
    755                      mOrigWindowType = mWindowAttributes.type;
    756                      mAttachInfo.mRecomputeGlobalAttributes = true;
    757                      collectViewAttributes();
    758                      res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
    759                              getHostVisibility(), mDisplay.getDisplayId(), mWinFrame,
    760                              mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
    761                              mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel);
    762                  } catch (RemoteException e) {
                    ...
                }
                        ...
    }
    

    758行,在setView方法中主要调用了mWindowSession的addToDisplay方法。mWindowSession属于IWindowSession类型,一个Binder对象,用于进行进程间通信,IWindowSession是Client端的代理,它的Server端的实现为Session,此前包含ViewRootImpl在内的代码逻辑都是运行在本地进程的,而Session的addToDisplay方法则运行在WMS所在的进程。

    
    class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
            final WindowManagerService mService;
            ...
            @Override
    201      public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
    202              int viewVisibility, int displayId, Rect outFrame, Rect outContentInsets,
    203              Rect outStableInsets, Rect outOutsets,
    204              DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel) {
    205          return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId, outFrame,
    206                  outContentInsets, outStableInsets, outOutsets, outDisplayCutout,           outInputChannel);
            ...
    207      }
    }
    

    到了最后,可以发现addView其实是WindowManagerService进行addWindow操作。

    Window的添加操作实际上是先通过WindowManagerGlobal对View进行第一步的处理,ViewRootImpl来进行界面的刷新,内部则通过Session与WindowManagerService进行跨进程通信,将添加的请求交给WindowManagerService来处理。

    相关文章

      网友评论

          本文标题:SystemUI(三)扒一扒WindowManager的addV

          本文链接:https://www.haomeiwen.com/subject/ioncnctx.html