博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android源码解析:UI绘制流程是如何开始的?
阅读量:7021 次
发布时间:2019-06-28

本文共 13143 字,大约阅读时间需要 43 分钟。

带着问题看源码

经过前几篇源码解析文章,我们了解到打开一个新的Activity界面,会执行到Activity的onCreate()方法,然后我们调用setContentView()方法传入希望展示的xml布局,但是我们传入的布局文件时如何展示在手机上的呢?带着这个问题,我们一起深入源码查找解惑

先看Activity的生命周期:

这张图不用多解释了吧!这里要讲的是用户看到Activity界面是在onResume方法调用的时候,而该方法也可以说是UI绘制的入口

UI绘制入口ActivityThread.handleResumeActivity()
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {        //...        //1.创建Activity实例,并调用onCreate()生命周期方法        Activity a = performLaunchActivity(r, customIntent);                if (a != null) {            r.createdConfig = new Configuration(mConfiguration);            reportSizeConfigurations(r);            Bundle oldState = r.state;            //2.调用onStart()->onResume()生命周期方法            handleResumeActivity(r.token, false, r.isForward,                    !r.activity.mFinished && !r.startsNotResumed, r.lastProcessedSeq, reason);            //...    }            final void handleResumeActivity(IBinder token,            boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) {        //拿到当前Activity保存的数据        ActivityClientRecord r = mActivities.get(token);                //...                //1.执行Activity的onStart()与onResume()生命周期方法        r = performResumeActivity(token, clearHide, reason);        if (r != null) {            final Activity a = r.activity;            //...            boolean willBeVisible = !a.mStartedActivity;            if (!willBeVisible) {                try {                    //标示将要进行界面展示                    willBeVisible = ActivityManager.getService().willActivityBeVisible(                            a.getActivityToken());                } catch (RemoteException e) {                    throw e.rethrowFromSystemServer();                }            }            if (r.window == null && !a.mFinished && willBeVisible) {                //2.下面这段代码主要操作逻辑为                r.window = r.activity.getWindow();                   View decor = r.window.getDecorView(); //通过Activity的PhoneWindow拿到DecorView                decor.setVisibility(View.INVISIBLE); //先设置DecorView不显示                ViewManager wm = a.getWindowManager(); //通过Activity拿到WindowManager                WindowManager.LayoutParams l = r.window.getAttributes();                a.mDecor = decor;                l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;                l.softInputMode |= forwardBit;                if (r.mPreserveWindow) {                    a.mWindowAdded = true;                    r.mPreserveWindow = false;                    ViewRootImpl impl = decor.getViewRootImpl();                    if (impl != null) {                        impl.notifyChildRebuilt();                    }                }                if (a.mVisibleFromClient) {                    if (!a.mWindowAdded) {                        a.mWindowAdded = true;                        //核心方法3.将DecorView添加到WindwoManager中                        wm.addView(decor, l);                       } else {                        a.onWindowAttributesChanged(l);                    }                }            //...            if (!r.activity.mFinished && willBeVisible                    && r.activity.mDecor != null && !r.hideForNow) {                if (r.newConfig != null) { //判断设置的Configureation是否改变了(设备旋转)                    performConfigurationChangedForActivity(r, r.newConfig);                    if (DEBUG_CONFIGURATION) Slog.v(TAG, "Resuming activity "                            + r.activityInfo.name + " with newConfig " + r.activity.mCurrentConfig);                    r.newConfig = null;                }                if (localLOGV) Slog.v(TAG, "Resuming " + r + " with isForward="                        + isForward);                WindowManager.LayoutParams l = r.window.getAttributes();                if ((l.softInputMode                        & WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION)                        != forwardBit) {                    l.softInputMode = (l.softInputMode                            & (~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION))                            | forwardBit;                    if (r.activity.mVisibleFromClient) { //跟新DecorView在Window上的布局展示                        ViewManager wm = a.getWindowManager();                        View decor = r.window.getDecorView();                        wm.updateViewLayout(decor, l);                    }                }                r.activity.mVisibleFromServer = true;                mNumVisibleActivities++;                if (r.activity.mVisibleFromClient) {                    r.activity.makeVisible();                }            }            if (!r.onlyLocalRequest) {                r.nextIdle = mNewActivities;                mNewActivities = r;                if (localLOGV) Slog.v(                    TAG, "Scheduling idle handler for " + r);                Looper.myQueue().addIdleHandler(new Idler());            }            r.onlyLocalRequest = false;            //4.通知AMS该Activity的生命周期onResume执行完毕            if (reallyResume) {                try {                    ActivityManager.getService().activityResumed(token);                } catch (RemoteException ex) {                    throw ex.rethrowFromSystemServer();                }            }        } else {            //异常情况,调用界面finish()            try {                ActivityManager.getService()                    .finishActivity(token, Activity.RESULT_CANCELED, null,                            Activity.DONT_FINISH_TASK_WITH_ACTIVITY);            } catch (RemoteException ex) {                throw ex.rethrowFromSystemServer();            }        }    }复制代码

将DecorView添加到WindwoManager中wm.addView(decor, l);

找到WindowManager的实现类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);    }}其中addView()方法真正的执行者是WindowManagerGlobal复制代码

WindowManagerGlobal.addView()

private final Object mLock = new Object();    private final ArrayList
mViews = new ArrayList
(); private final ArrayList
mRoots = new ArrayList
(); private final ArrayList
mParams = new ArrayList
(); public void addView(View view, ViewGroup.LayoutParams params, Display display, Window parentWindow) { //...各种判断 final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params; if (parentWindow != null) { parentWindow.adjustLayoutParamsForSubWindow(wparams); } else { final Context context = view.getContext(); if (context != null&& (context.getApplicationInfo().flags& ApplicationInfo.FLAG_HARDWARE_ACCELERATED) != 0) { wparams.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED; } } ViewRootImpl root; View panelParentView = null; synchronized (mLock) { //先锁住 //... //新建ViewRootImpl实例 root = new ViewRootImpl(view.getContext(), display); view.setLayoutParams(wparams); //缓存,提高性能 //mViews保存的是View对象,DecorView //mRoots保存和顶层View关联的ViewRootImpl对象 //mParams保存的是创建顶层View的layout参数。 mViews.add(view); mRoots.add(root); mParams.add(wparams); //核心方法:调用ViewRootImpl.setView()方法 try { root.setView(view, wparams, panelParentView); } catch (RuntimeException e) { // BadTokenException or InvalidDisplayException, clean up. if (index >= 0) { removeViewLocked(index, true); } throw e; } } }复制代码

核心方法:调用ViewRootImpl.setView()方法

public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {        synchronized (this) {            if (mView == null) {//只能调用一次                mView = view; //赋值                                // ...                                //1.调用requestLayout()                requestLayout();                //...                //设置DecorView的parent为ViewRootImpl                view.assignParent(this);                                 //...            }        }    }    @Override    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();        }    }    //执行mTraversalRunnable的run方法    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;            }        }    }    private void performTraversals() {                // ...            if (!mStopped || mReportNextDraw) {                boolean focusChangedDueToTouchMode = ensureTouchModeLocally(                        (relayoutResult&WindowManagerGlobal.RELAYOUT_RES_IN_TOUCH_MODE) != 0);                if (focusChangedDueToTouchMode || mWidth != host.getMeasuredWidth()                        || mHeight != host.getMeasuredHeight() || contentInsetsChanged ||                        updatedConfiguration) {                    int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);                    int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);                    if (DEBUG_LAYOUT) Log.v(mTag, "Ooops, something changed! mWidth="                            + mWidth + " measuredWidth=" + host.getMeasuredWidth()                            + " mHeight=" + mHeight                            + " measuredHeight=" + host.getMeasuredHeight()                            + " coveredInsetsChanged=" + contentInsetsChanged);                     // 1.测量                    performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);                    // Implementation of weights from WindowManager.LayoutParams                    // We just grow the dimensions as needed and re-measure if                    // needs be                    int width = host.getMeasuredWidth();                    int height = host.getMeasuredHeight();                    boolean measureAgain = false;                    if (lp.horizontalWeight > 0.0f) {                        width += (int) ((mWidth - width) * lp.horizontalWeight);                        childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(width,                                MeasureSpec.EXACTLY);                        measureAgain = true;                    }                    if (lp.verticalWeight > 0.0f) {                        height += (int) ((mHeight - height) * lp.verticalWeight);                        childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(height,                                MeasureSpec.EXACTLY);                        measureAgain = true;                    }                    if (measureAgain) {                        //再次测量                        performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);                    }                    layoutRequested = true;                }            }        } else {            maybeHandleWindowMove(frame);        }        final boolean didLayout = layoutRequested && (!mStopped || mReportNextDraw);        boolean triggerGlobalLayoutListener = didLayout                || mAttachInfo.mRecomputeGlobalAttributes;        if (didLayout) {                        //2.布局            performLayout(lp, mWidth, mHeight);           // ...        if (!cancelDraw && !newSurface) {            if (mPendingTransitions != null && mPendingTransitions.size() > 0) {                for (int i = 0; i < mPendingTransitions.size(); ++i) {                    mPendingTransitions.get(i).startChangingAnimations();                }                mPendingTransitions.clear();            }            //3.绘制            performDraw();        } else {            if (isViewVisible) {                // Try again                scheduleTraversals();            } else if (mPendingTransitions != null && mPendingTransitions.size() > 0) {                for (int i = 0; i < mPendingTransitions.size(); ++i) {                    mPendingTransitions.get(i).endChangingAnimations();                }                mPendingTransitions.clear();            }        }        mIsInTraversal = false;    }复制代码

在performTraversals()方法中,执行测量performMeasure(),布局performLayout(),绘制performDraw(),这三个方法最终都会调用View的相对应方法 UML调用时序图:

转载地址:http://cndxl.baihongyu.com/

你可能感兴趣的文章
android线程使用注意问题?【安卓进化二】
查看>>
常用JS方法
查看>>
hive优化--增加减少map数
查看>>
php-fpm配置
查看>>
【 D3.js 选择集与数据详解 — 2 】 使用data()绑定数据
查看>>
SomethingOn生产力提升工具使用
查看>>
beyond programming
查看>>
【转】NET-SNMP安装过程
查看>>
2012-06-18 16:20 ECSHOP用URL重写进行SEO优化
查看>>
Tomcat Server的结构图
查看>>
Nginx RPM包SPEC文件
查看>>
亲测CentOS 6.6 x86_64下源码安装LAMP平台(APACHE 2.4.16+MYSQL 5.6.17+PHP 5.6.7)
查看>>
python 一个XML解析
查看>>
温故而知新Android篇之三
查看>>
oracle的索引
查看>>
Java执行Runtime.exec(shell)报Cannot allocate memory
查看>>
ADT中通过DDMS导入文件出错ddms transfer error: Read-only file system,Failed to push selection...
查看>>
mac 10.11.6 root没有最高权限解决方案
查看>>
tomcat+nginx 以https方式访问
查看>>
camel 项目中用到的功能(一)
查看>>