美文网首页面试
Activity 视图显示

Activity 视图显示

作者: 杨殿生 | 来源:发表于2019-08-16 09:56 被阅读0次

    一、创建给Window添加布局视图

    创建显示Activity视图,需要调用setContentView()

    public void setContentView(int layoutResID){
       getWindow().setContentView(layoutResID);
       initWindowDecorActionBar();
    }
    

    二、Window何时创建

    getWindow() 中的window是在创建Activity时调用scheduleLaunchActivity()中的attach()创建的phoneWindow,并设置WindowManager

     final void attach(Context context, ActivityThread aThread,
            Instrumentation instr, IBinder token, int ident,
            Application application, Intent intent, ActivityInfo info,
            CharSequence title, Activity parent, String id,
            NonConfigurationInstances lastNonConfigurationInstances,
            Configuration config, String referrer, IVoiceInteractor voiceInteractor) {
        ....
        mWindow = new PhoneWindow(this, window); //在这里直接new一个Window
        mWindow.setCallback(this);//设置回调接口,当window接收系统发送给它的例如键盘和触摸屏事件,就可以通知Activity,Activity做出相应的处理
        .....
        //设置窗口管理器
        mWindow.setWindowManager(
             (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
                mToken, mComponent.flattenToString(),
                (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
        .....
        }
    

    三、Window、WindowManager和WindowManagerServer关系

    Window是这三者的核心,起到了桥梁的作用,她是一个抽象类,主要定义了一些对Window操作的抽象方法。WindowManager主要是管理Window是一个接口类,他继承自ViewManager接口,主要定义了一些对View的操作和一些常量,例如:添加View,移除View,删除View。WindowManagerServer就是位于 Framework 层的窗口管理服务,它的职责就是管理系统中的所有窗口,通过Binder连接WindowManager与Window之间的的通信,即WindowManager通过WindowManagerServer操作Window。

    四、构建View树

    DecorView布局

    setContentView(layoutResID); 会创建一个DecorView然后给DecorView添加content,也就是我们自己的布局、这样我们的View树就构建好了,但是还是没有到屏幕上

    五、显示View到屏幕上

    scheduleLaunchActivity中会调用handleResumeActivity方法,首先会调用 Activity 的 onResume 方法,然后会获取ViewManager添加关联
    接着会调用 Activity 的 makeVisible() 方法,正是在 makeVisible 方法中,DecorView 才真正的完成了显示过程,到这里 Activity 的视图才能被用户看到

        void makeVisible() {  
          if (!mWindowAdded) {     
           ViewManager wm = getWindowManager(); //获得WindowManager(WindowManager extends ViewManager)
           wm.addView(mDecor, getWindow().getAttributes());   //将DecorView加入到Window中
           mWindowAdded = true;   
          }   
          mDecor.setVisibility(View.VISIBLE);
        }
    
     public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
          applyDefaultToken(params);
          mGlobal.addView(view, params, mDisplay, mParentWindow);
      }
    

    ViewManager 只是一个接口,它的实现类为 WindowManagerImpl。在 WindowManagerImpl 我查找 addView() 方法
    这里的 mGlobal 又是 WindowManagerGlobal 的实例。所有我们又要跳转到 WindowManagerGlobal.addView() 。

    public void addView(View view, ViewGroup.LayoutParams params, Display display, Window parentWindow) {
            ViewRootImpl root;
            View panelParentView = null;
            synchronized (mLock) 
                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);
                }
            }
        }
    

    获取PhoneWindow以及DecorView、LayoutParams,调用WindowManagerImpl的addView,创建ViewRoot,然后将三者关联。并将params和父布局params设置到ViewRoot中。
    接下来ViewRoot会调用requestLayout对应用程序窗口UI做第一次布局。
    调用IWindowSession的add方法,通知WMS创建一个WindowState。这里会把W对象传过去,以便WMS可以和应用进程通讯。

    setView中会调用requestLayout

    public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
            synchronized (this) {
                    ……
                    requestLayout();
                     ……
                    view.assignParent(this);
                    ……
                }
            }
        }
    

    ViewRootImpl在requestLayout的时候将一个Runnable交由Choreographer去调度,让它能够在下一个绘制帧时执行它。这个Runnable内只有一条语句,就是执行doTraversal,主要的内容在其中执行的performTraversal中,这个函数非常非常长,做的事情大致就是从顶至下的measure/layout/draw,通知ViewTreeObserver的各类Listener也大部分都是在这一步中完成的。

    public void requestLayout() {
        if (!mHandlingLayoutInLayoutRequest) {
            checkThread();
            mLayoutRequested = true;
            scheduleTraversals();
        }
    }
    

    会添加消息栅栏,发送一个异步消息。消息栅栏会拦截所有的普通消息,但不会拦截异步消息

    void scheduleTraversals() {
         if (!mTraversalScheduled) {
             mTraversalScheduled = true;
             mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
             mChoreographer.postCallback(
                     Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
             if (!mUnbufferedInputDispatch) {
                 scheduleConsumeBatchedInput();
             }
             notifyRendererOfFramePending();
             pokeDrawLockIfNeeded();
         }
     }
    

    Vsync信号到来,执行Runnable

    final class TraversalRunnable implements Runnable {
        @Override
        public void run() {
            doTraversal();
        }
    }
    
    void doTraversal() {
        if (mTraversalScheduled) {
            mTraversalScheduled = false;
            mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
    
            if (mProfile) {
                Debug.startMethodTracing("ViewAncestor");
            }
    
            performTraversals();
    
            if (mProfile) {
                Debug.stopMethodTracing();
                mProfile = false;
            }
        }
    }
    

    performTraversals() 会执行 performMeasure 、 performLayout、 performDraw 这里就不用多说了吧。也就解释了为啥 View 的绘制顺序是 measure -> layout -> draw 了吧

    参考
    https://fourfire.top/#/Android_Framework/View%E6%98%AF%E6%80%8E%E4%B9%88%E7%94%BB%E5%87%BA%E6%9D%A5%E7%9A%84%EF%BC%88%E5%9B%9B%EF%BC%89%E2%80%94%E2%80%94%E5%BA%94%E7%94%A8%E7%A8%8B%E5%BA%8F%E7%AA%97%E5%8F%A3?id=%e5%85%b3%e7%b3%bb%e6%a6%82%e8%bf%b0
    https://www.jianshu.com/p/456b35f35626
    https://www.jianshu.com/p/6a3bca1b36e8
    https://www.jianshu.com/p/9acdf27aae06
    https://blog.csdn.net/dongge825/article/details/54412723
    https://juejin.im/post/5a61973bf265da3e2d338196
    https://cloud.tencent.com/developer/article/1154082
    https://blog.csdn.net/qian520ao/article/details/80954626

    相关文章

      网友评论

        本文标题:Activity 视图显示

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