美文网首页
View加载和绘制

View加载和绘制

作者: vpractical | 来源:发表于2019-12-26 20:57 被阅读0次

    [TOC]

    Activity的相关生命周期

    ActivityThread中:

    private Activity performLaunchActivity(){
        ...
        ContextImpl appContext = createBaseContextForActivity(r);
        java.lang.ClassLoader cl = appContext.getClassLoader();
        //创建activity对象
        Activity activity = null;
        activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);
    
        Window window = null;
        if (r.mPendingRemoveWindow != null && r.mPreserveWindow) {
            window = r.mPendingRemoveWindow;
        }
        
        //调用Activity的attach()
        activity.attach(...,window,...)
        
        //调用Activity的onPerfermCreate()->onCreate()
        mInstrumentation.callActivityOnCreate(activity, r.state);
    }
    
    • r是ActivityClientRecord对象,每个activity启动前会创建一个,用于保存:
      • Binder对象
      • Intent对象
      • Bundle对象
      • Window对象
      • ActiityInfo对象,他包含theme,launcherMode,permission,taskAffinity,flags等
      • Activity对象本身和上级Activity对象
      • 各种Configuration
      • 生命周期状态等

    Activity的attach()中:

    final void attach(...){
        mWindow = new PhoneWindow(this, window, activityConfigCallback);
        ...
        //mToken是当前Activity的IBinder对象,传递给WMS进程
        mWindow.setWindowManager((WindowManager)context.getSystemService(Context.WINDOW_SERVICE),mToken,...);
        if (mParent != null) {
            mWindow.setContainer(mParent.getWindow());
        }    
        mWindowManager = mWindow.getWindowManager();
    }
    

    View加载

    ActivityThread中:

    public void handleResumeActivity(...){
        final ActivityClientRecord r = mActivities.get(token);
        final Activity a = r.activity;
        
        if (r.window == null && !a.mFinished && willBeVisible) {
            //获取PhoneWindow对象
            r.window = r.activity.getWindow();
            //r.window是Window的实现类phoneWindow对象,实现方法getDecorView()中创建了DecorView
            //获取DecorView对象
            View decor = r.window.getDecorView();
            decor.setVisibility(View.INVISIBLE);
            //前面Activity的attach()中初始化了WindowManager
            //这里获取了WindowManagerImpl的对象
            ViewManager wm = a.getWindowManager();
            WindowManager.LayoutParams l = r.window.getAttributes();
            a.mDecor = decor;
            wm.addView(decor, l);
        }        
    }
    
    • WindowManager是个接口,管理window对象,这里调用了实现类WindowManagerImpl的addView(),通过桥接模式又调用了WindowManagerGlobal的addView()
    • WindowManagerGlobal是单例,保存了所有Window对象和ViewRootImol对象和LayoutParams对象,通过对比activity的token(Binder)和这3个对象的token判断是哪个activity的
    public void addView(View view, ViewGroup.LayoutParams params,...){
        ViewRootImpl root = new ViewRootImpl(view.getContext(), display);
        view.setLayoutParams(wparams);
        final int count = mViews.size();
        for (int i = 0; i < count; i++) {
            if (mRoots.get(i).mWindow.asBinder() == wparams.token) {
                panelParentView = mViews.get(i);
            }
        }    
        root.setView(view, wparams, panelParentView);
    }
    
    • ViewRootImpl管理view,surface,与WMS通信

    ViewRootImpl的setView()

        public void setView(View view,...){
            ...
            requestLayout();
            //IWindowSession是远程接口代理,WMS的Binder对象,这里是通知WMS渲染
            res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                                getHostVisibility(), mDisplay.getDisplayId(), mTmpFrame,
                                mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                                mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel,
                                mTempInsets);
            setFrame(mTmpFrame);
        }
    
        public void requestLayout() {
            if (!mHandlingLayoutInLayoutRequest) {
                //这里会检查是否主线程
                checkThread();
                mLayoutRequested = true;
                scheduleTraversals();
            }
        }
        //间接调用到
        private void performTraversals(){
            //生成测量规则,这是一个32位2进制数,前2位表示测量模式,后30位表示大小
            int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);
            int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);
            
            performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
            //调用到View的measure方法,这里是DecorView对象,所以调用到FrameLayout的onMeasure()
            //mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
            
            performLayout(lp, mWidth, mHeight);
            //mView.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
            performDraw();
        }
    

    Framelayout中:

    onMeasure

    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int count = getChildCount();
        for (int i = 0; i < count; i++) {
                final View child = getChildAt(i);
                if (mMeasureAllChildren || child.getVisibility() != GONE) {
                    //这里传入子view和父容器的测量规则,调用子view的测量方法
                    //child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
                    measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0);
                    final LayoutParams lp = (LayoutParams) child.getLayoutParams();
                    //FrameLayout的宽高是child中最宽或最高的那个
                    maxWidth = Math.max(maxWidth,child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin);
                    maxHeight = Math.max(maxHeight,child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin);
                }
        }
        setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, childState),resolveSizeAndState(maxHeight, heightMeasureSpec,childState << MEASURED_HEIGHT_STATE_SHIFT));
        
        //如果Framelayout不是精确模式,即宽高是Wrap,宽或高为Match的child会受他的最终大小影响,所以在此调用这些child的再次测量
        for (int i = 0; i < count; i++) {
            final View child = mMatchParentChildren.get(i);
            ...
            child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
        }
    }
    

    onLayout

    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        layoutChildren(left, top, right, bottom, false);
    }
    
    void layoutChildren(int left, int top, int right, int bottom, boolean forceLeftGravity) {
        final int count = getChildCount();
        for (int i = 0; i < count; i++) {
            final View child = getChildAt(i);
            ...
            child.layout(childLeft, childTop, childLeft + width, childTop + height);
        }    
    }
    

    onDraw

    ViewRootImpl的performDraw()会调用到

    public final Surface mSurface = new Surface();
    
    private boolean drawSoftware(Surface surface,Rect dirty,...){
        final Canvas canvas;
        //view绘制用的画布,是在Surface对象上截取的一个rect范围
        //mDirty.set(0, 0, mWidth, mHeight);DecorView的范围是Window的宽高
        canvas = mSurface.lockCanvas(dirty);
        canvas.setDensity(mDensity);
        //这里会调用onDraw(),容器是空实现,非容器View绘制视图
        mView.draw(canvas);
    }
    
    draw方法6步:
    
        *      1. Draw the background
        *      2. If necessary, save the canvas' layers to prepare for fading
        *      3. Draw view's content
        *      4. Draw children
        *      5. If necessary, draw the fading edges and restore layers
        *      6. Draw decorations (scrollbars for instance)
    

    关键环节

    • Activity创建后调用的attach方法中,初始化了PhoneWindow对象,WindowManager对象
    • WindowManager初始化时,赋值的是WindowManagerImpl对象
    • PhoneWindow实现了Window的getDecorView方法,这里创建了DecorView对象
    • handleResumeActivity()中获取了decorView对象和wm的params,由wm开始addView,wm是window的管理器,addview中创建了ViewRootImpl对象,这是view树的根和管理器
    • ViewRootImpl的setView被wm触发后,调用requestLayout,这里开始view三步骤

    关于测量2次

    performTranversal被执行2次

    关于测量模式

    • EXACTLY:表示设置了精确的值,一般当View或childView设置其宽、高为精确值、match_parent时,会将其设置为EXACTLY
    • AT_MOST:表示子布局被限制在一个最大值内,一般当View或childView设置其宽高为wrap_content时,会将其设置为AT_MOST
    • UNSPECIFIED:表示子布局想多大多大,一般出现在AadapterView的item的heightMode中、ScrollView的childView的heightMode中

    相关文章

      网友评论

          本文标题:View加载和绘制

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