Activity页面加载流程(二)

作者: SHHO | 来源:发表于2019-03-04 21:44 被阅读76次

    接上一篇《Activity页面加载流程(一)》

    上一篇讲了Window的创建,但其显示流程还没有讲清楚就跑路了

    废话不多说,我们continue
    PS:英文用错了场景别笑话,谁让它是关键词字😊😊
            这个单词拼不成汉语吧😊😊

    WindowManager、WindowManagerImpl和WindowManagerGlobal的关系及内部机制

    WindowManager是一个继承于ViewManager的接口,实现类是WindowManagerImpl
    Activity.java

    final void attach(...){
      ...
      mWindow.setWindowManager(
      (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),  //系统的WindowManger
            mToken, mComponent.flattenToString(),
            (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
      ...
      mWindowManager = mWindow.getWindowManager();
    }
    

    Window.java

    public void setWindowManager(WindowManager wm, IBinder appToken, String appName, boolean hardwareAccelerated) {
      ...
      //wm的createLocalWindowManager方法又重新new了WindowManagerImpl
      mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
    }
    
    public WindowManager getWindowManager() {
      return mWindowManager;
    }
    

    WindowManagerImpl.java
    WindowManagerImpl是WindowManager的实现类,显实现了addView、updateViewLayout、removeView等方法,可是这哥们胸怀宇宙,有空还要看星星,别看它是一个实现类,名字还带一个Impl,却把具体工作都交给了单例的WindowManagerGlobal。

    public final class WindowManagerImpl implements WindowManager {
      //全局单例
      private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
    
      ...
      @Override
      public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
        applyDefaultToken(params);
        mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
      }
    
      @Override
      public void updateViewLayout(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
        applyDefaultToken(params);
        mGlobal.updateViewLayout(view, params);
      }
    
      @Override
      public void removeView(View view) {
        mGlobal.removeView(view, false);
      }
      ...
    }
    

    WindowManagerGlobal.java
    WindowManagerGlobal是单例的,所以它内部用几个集合来保存Window及参数和所对应的View

    //每个Window对应的View
    private final ArrayList<View> mViews = new ArrayList<View>();
    //每个Window对应的ViewRootImpl
    private final ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>();
    //每个Window的参数
    private final ArrayList<WindowManager.LayoutParams> mParams = new ArrayList<WindowManager.LayoutParams>();
    
    public void addView(View view, ViewGroup.LayoutParams params,
                Display display, Window parentWindow) {
    
      ViewRootImpl root;
      ...
      //创建ViewRootImpl,View的invalidate更新view的时候,就是从ViewRootImpl开始的
      root = new ViewRootImpl(view.getContext(), display);
      view.setLayoutParams(wparams);
      ....
      //上面的三个集合
      mViews.add(view);
      mRoots.add(root);
      mParams.add(wparams);
    
      // do this last because it fires off messages to start doing things
      try {
        //重要方法
        root.setView(view, wparams, panelParentView);
      }
      ...
    }
    

    Window的显示

    WindowManagerService作为一个系统级的服务运行在一个单独的进程,所以WindowManager和它之间的交互是一个IPC(进程间通信)过程,ViewRootImpl充当了桥梁的作为

    通过Binder机制获取WMS,在WindowManagerService获取舒适化Session,进而通过session的addToDisplay方法和WMS的addWindow添加到将Window添加到设备

    ViewRootImpl.java

    final IWindowSession mWindowSession;
    
    public ViewRootImpl(Context context, Display display) {
      ...
      //在构造方法里调用WindowManagerGlobal的static方法getWindowSession()初始化IWindowSession
      mWindowSession = WindowManagerGlobal.getWindowSession();
      ...
    }
    
    public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
      ...
      //开始View的三大流程,测量、布局和绘制
      requestLayout();
      ...
      try {
        ...
        //显示
        res = mWindowSession.addToDisplay(mWindow,  ...);
        ...
      } 
      ...
    }
    

    WindowManagerGlobal.java

    public static IWindowSession getWindowSession() {
      synchronized (WindowManagerGlobal.class) {
        if (sWindowSession == null) {
          try {
            InputMethodManager imm = InputMethodManager.getInstance();
            IWindowManager windowManager = getWindowManagerService();
            //从WindowManagerService里获取WindowSession
            sWindowSession = windowManager.openSession(
              new IWindowSessionCallback.Stub() {
                @Override
                public void onAnimatorScaleChanged(float scale) {
                  ValueAnimator.setDurationScale(scale);
                }
              },
              imm.getClient(), imm.getInputContext());ffgetWindowManagerService
          } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
          }
        }
      return sWindowSession;
      }
    }
    
    public static IWindowManager getWindowManagerService() {
      synchronized (WindowManagerGlobal.class) {
        if (sWindowManagerService == null) {
          //从binder里获取WindowManagerService
          sWindowManagerService = IWindowManager.Stub.asInterface(ServiceManager.getService("window"));
          try {
            if (sWindowManagerService != null) {
              ValueAnimator.setDurationScale(sWindowManagerService.getCurrentAnimatorScale());
            }
          } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
          }
        }
      return sWindowManagerService;
      }
    }
    

    WindowManagerService.java

    @Override
    public IWindowSession openSession(IWindowSessionCallback callback, IInputMethodClient client, IInputContext inputContext) {
      if (client == null) throw new IllegalArgumentException("null client");
      if (inputContext == null) throw new IllegalArgumentException("null inputContext");
      //Session就在这里创建,Session和WindowManagerService相互持有
      Session session = new Session(this, callback, client, inputContext);
      return session;
    }
    

    Session.java

    @Override
    public int addToDisplay(IWindow window, ...) {
      //这里调用WMS的addWindow方法
      return mService.addWindow(this, window, ...);
    }
    

    Window已经显示了
    Activity的页面加载流程已经结束,涉及到的类比较多,可能有说的不明的或错误的地方,请谅解


    源码一个class动辄万行,内部类N多个
    是不是脑壳疼
    疼就对了
    不然你以为你zou是谷歌开发工程师了


    不进则退
    学习还是必须的
    没有什么比自身的强大更重要
    你想要的
    时间都会给你

    学会自我约束
    才能自我自由

    鸡汤是给你们喝的,我喜欢吃肉

    End

    相关文章

      网友评论

        本文标题:Activity页面加载流程(二)

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