美文网首页
Android_窗口绘制相关流程

Android_窗口绘制相关流程

作者: 冉桓彬 | 来源:发表于2017-04-23 23:34 被阅读60次

    看到setContentView时, 感觉又要把Activity的启动流程看一遍, 然后又要继续往上看, 不知道何时才能正式进入窗口绘制流程, 下面先把需要做的准备工作记录下来:

    1、Windows.java->Callback.class;

    1、先从ActivityThread入手:

    private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
        ...
        Activity a = performLaunchActivity(r, customIntent);
        ...
    }
    
    private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        ...
        Activity activity = null;
        try {
            java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
            activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);
        }
        ...
        if (activity != null) {
            Context appContext = createBaseContextForActivity(r, activity);
            ...
            Window window = null;
            activity.attach(appContext, this, getInstrumentation(), r.token,
                            r.ident, app, r.intent, r.activityInfo, title, r.parent,
                            r.embeddedID, r.lastNonConfigurationInstances, config,
                            r.referrer, r.voiceInteractor, window);
        ...
        }
    }
    
    1、ClassLoader加载对应的Activity.class文件
    
    2、createBaseContextForActivity(r, activity);
    
    private Context createBaseContextForActivity(ActivityClientRecord r, final Activity activity) {
        ...
        ContextImpl appContext = ContextImpl.createActivityContext(this, r.packageInfo, r.token, displayId, r.overrideConfig);
        appContext.setOuterContext(activity);
        Context baseContext = appContext;
        ...
        return baseContext;
    }
    
    3、activity.attach():
    

    2、Activity.java

    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,
                      Window window) {
            attachBaseContext(context);
            mWindow = new PhoneWindow(this, window);
            mWindow.setCallback(this);
            mWindow.getLayoutInflater().setPrivateFactory(this);
            mInstrumentation = instr;
            mToken = token;
            mActivityInfo = info;
            mParent = parent;
            mWindow.setWindowManager(
                    (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
                    mToken, mComponent.flattenToString(),
                    (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
            if (mParent != null) {
                mWindow.setContainer(mParent.getWindow());
            }
            mWindowManager = mWindow.getWindowManager();
        }
    
    • 调用setCallback将window与activity产生关联, 而window实际上是PhoneWindow; 切入到Window中去观察setCallback();
    public void setCallback(Callback callback) {
        mCallback = callback;
    }
    public interface Callback {
        ...
        public boolean dispatchTouchEvent(MotionEvent event);
        public void onWindowFocusChanged(boolean hasFocus);
        ...
    }
    
    • Callback是一系列的回调函数的集合, 先记下来以后再看看是如何实现回调的

    从上面代码可以试着分析一波WindowManager, ViewManager, WindowManagerImpl, PhoneWindow, Window的关系

    public class PhoneWindow extends Window{...}
    public abstract class Window{...}
    public final class WindowManagerImpl implements WindowManager{...}
    public interface WindowManager extends ViewManager {...}
    public interface ViewManager{...}
    
    Window mWindow = new PhoneWindow(this, window);
    public PhoneWindow(Context context) {
        super(context);
        mLayoutInflater = LayoutInflater.from(context);
    }
    public PhoneWindow(Context context, Window preservedWindow) {
        this(context);
    }
    
    
    • 将mWindow实际上指向子类PhoneWindow;
    mWindow.setWindowManager(
               (WindowManager)context.getSystemService(Context.WINDOW_SERVICE), 
                mToken, 
                mComponent.flattenToString(), 
                (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
    public void setWindowManager(WindowManager wm, IBinder appToken, String appName, boolean hardwareAccelerated) {
          if (wm == null) {
              wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
          }
          mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
    }
    private WindowManager mWindowManager;
    private WindowManagerImpl(Context context, Window parentWindow) {
          mContext = context;
          mParentWindow = parentWindow;
    }
    public WindowManagerImpl createLocalWindowManager(Window parentWindow) {
          return new WindowManagerImpl(mContext, parentWindow);
    }
    private final Window mParentWindow;
    
    • 1、WindowManagerImpl中的mParent实际上指向的是PhoneWindow;
    • 2、mWindowManager实际上指向的WindowManagerImpl;
    private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        ...
        if (r.isPersistable()) {
            mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
        } else {
            mInstrumentation.callActivityOnCreate(activity, r.state);
        }
        ...
    }
    
    • 1、isPersistable关于持久化存储的一个玩意儿, 先记下来, 留待以后分析
    • 2、目前先重点分析callActivityOnCreate(activity, r.state)方法;
    public class Instrumentation {
          public void callActivityOnCreate(Activity activity, Bundle icicle) {
              prePerformCreate(activity);
              activity.performCreate(icicle);
              postPerformCreate(activity);
          }
    }
    class->Instrumentation->
    public void callActivityOnCreate(Activity activity, Bundle icicle) {
          prePerformCreate(activity);
          activity.performCreate(icicle);
          postPerformCreate(activity);
    }
    class->Activity->
    final void performCreate(Bundle icicle) {
          restoreHasCurrentPermissionRequest(icicle);
          onCreate(icicle);
          mActivityTransitionState.readState(icicle);
          performCreateCommon();
    }
    protected void onCreate(@Nullable Bundle savedInstanceState) {
          if (mLastNonConfigurationInstances != null) {
              mFragments.restoreLoaderNonConfig(mLastNonConfigurationInstances.loaders);
          }
          if (savedInstanceState != null) {
              mFragments.restoreAllState(p, mLastNonConfigurationInstances != null
                        ? mLastNonConfigurationInstances.fragments : null);
          }
          mFragments.dispatchCreate();
    }
    
    • 1、onCreate()方法由performLaunchActivity调用
    • 2、注意到mFragments与attach方法中都有mFragments出现, 先记下来, 以后分析.

    **onCreate()方法被调用了, 我们通常在onCreate()里面调用setContentView()方法对窗口进行绘制;

    3、setContentView:

    class Activity->
    public void setContentView(@LayoutRes int layoutResID) {
        getWindow().setContentView(layoutResID);
        initWindowDecorActionBar();
    }
    public Window getWindow() {
        return mWindow;
    }
    
    • 前面在attach()方法时已经将PhoneWindow赋值给了Window. 所以切入到PhoneWindow
    class PhoneWindow->
    @Override
    public void setContentView(int layoutResID) {
          if (mContentParent == null) {
              installDecor();
          }
    }
    

    第一次进入onCreate方法调用setContentView方法时, mContentParent=null; 切入到installDecor方法中

    class PhoneWindow->
    private void installDecor() {
        if (mDecor == null) {
            mDecor = generateDecor(-1);
        } 
        if (mContentParent == null) {
            mContentParent = generateLayout(mDecor);
        }
    }
    

    此时mDecor = null; 切入到generateDecor(-1)方法

    class PhoneWindow->
    protected DecorView generateDecor(int featureId) {
        return new DecorView(context, featureId, this, getAttributes());
    }
    class DecorView->
    DecorView(Context context, int featureId, PhoneWindow window, WindowManager.LayoutParams params) {
        super(context);
        setWindow(window);
    }
    void setWindow(PhoneWindow phoneWindow) {
        mWindow = phoneWindow;
    }
    private PhoneWindow mWindow;
    
    • 1、创建DecorView对象, 并对DecorView中的PhoneWindow进行赋值.
    • 2、前文中的attach种进行了mWindow.setCallback(this)将PhoneWindow, Activity, Callback三者绑定了关系, 这里又将PhoneWindow赋值给DecorView中的PhoneWindow, 也就是将PhoneWindow, Activity, Callback, DecorView四者产生了关联;

    然后切入到generateLayout();方法

    protected ViewGroup generateLayout(DecorView decor) {
        ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
        return contentParent;
    }
    

    暂时还没发生contentParent的作用, 先记下, 以后遇到大佬赶紧问一波

    目前发现好像就只做了几件事:

    1、初始化DecorView,将PhoneWindow, Activity, Callback, DecorView产生联系;
    2、初始化ViewGroup mContentParent;
    

    然后继续切入到handleLaunchActivity方法:

    class ActivityThread->
    private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
        Activity a = performLaunchActivity(r, customIntent);
        if (a != null) {
            handleResumeActivity(r.token, false, r.isForward, !r.activity.mFinished && !r.startsNotResumed, r.lastProcessedSeq, reason);
        }
    }
    

    4、resume->绘制三部曲:

    继续进入到handleResumeActivity()方法发现里面依次调用了measure, layout, draw方法;但是流程感觉很复杂, 估计这次看完, 后面有时间还会回来反复再看几遍.

    class ActivityThread->
    final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) {
        ...
        ActivityClientRecord r = mActivities.get(token);
        r = performResumeActivity(token, clearHide, reason);
        ...
    }
    class ActivityThread->
    public final ActivityClientRecord performResumeActivity(IBinder token, boolean clearHide, String reason) {
        ActivityClientRecord r = mActivities.get(token);
        if (r != null && !r.activity.mFinished) {
            try {
                 r.activity.performResume();
            } 
        }
        return r;
    }
    class Activity->
    final void performResume() {
        performRestart();
        mFragments.execPendingActions();
        mInstrumentation.callActivityOnResume(this);
        mFragments.dispatchResume();
        mFragments.execPendingActions();
        onPostResume();
    }
    class Instrumentation->
    public void callActivityOnResume(Activity activity) {
        activity.onResume();
    }
    
    • 貌似performResumeActivity()就做了一件事, 调用activity的onResume()方法;

    然后继续handleResumeActivity方法:

    class ActivityThread->
    final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) {
        ActivityClientRecord r = mActivities.get(token);
        r = performResumeActivity(token, clearHide, reason);
        if (r != null) {
            final Activity a = r.activity;
            if (r.window == null && !a.mFinished && willBeVisible) {
                r.window = r.activity.getWindow();
                View decor = r.window.getDecorView();
                ViewManager wm = a.getWindowManager();
                a.mDecor = decor;
                if (a.mVisibleFromClient && !a.mWindowAdded) {
                    a.mWindowAdded = true;
                    wm.addView(decor, l);
                }
            } 
            if (!r.activity.mFinished && willBeVisible && r.activity.mDecor != null && !r.hideForNow) {
                if (r.activity.mVisibleFromClient) {
                    r.activity.makeVisible();
                }
            }
        } 
    }
    class Activity->
    void makeVisible() {
        if (!mWindowAdded) {
            ViewManager wm = getWindowManager();
            wm.addView(mDecor, getWindow().getAttributes());
            mWindowAdded = true;
        }
        mDecor.setVisibility(View.VISIBLE);
    }
    
    • 1、r.window = activity.getWindow()将PhoneWindow赋值给ActivityClientRecord中的Window;
    • 2、a.getWindowManager()将WindowManagerImpl赋值给ViewManager;
    • 3、wm.addView(decor, l);接下来重点分析一波
    • 4、然后调用mDecor.setVisibility(View.VISIBLE); 进行UI显示;

    我们切入到addView里面去看看:

    addView最终在WindowManagerImpl中进行的实现;
    
    class WindowManagerImpl->
    @Override
    public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
        mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
    }
    private final Window mParentWindow;
    class WindowManagerGlobal->
    public void addView(View view, ViewGroup.LayoutParams params, Display display, Window parentWindow) {
        final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
        ViewRootImpl root;
        View panelParentView = null;
        synchronized (mLock) {
           int index = findViewLocked(view, false);
           if (index >= 0) {
               root = new ViewRootImpl(view.getContext(), display);
               view.setLayoutParams(wparams);
               mViews.add(view);
               mRoots.add(root);
               mParams.add(wparams);
           }
           try {
               root.setView(view, wparams, panelParentView);
           } 
        }
    }
    private int findViewLocked(View view, boolean required) {
        final int index = mViews.indexOf(view);
        return index;
    }
    class ViewRootImpl->
    public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
        synchronized (this) {
            if (mView == null) {
                mView = view;
                requestLayout();
            }
        }
    }
    View mView;
    

    这部分代码做了一下几件事:

    • 1、创建ViewRootImpl对象
    • 2、root.setView(view)将DecorView赋值给View;
    • 3、调用requestLayout()方法;

    5、绘制三部曲--requestLayout()方法:

    先看一看ViewRootImp的结构:

    public final class ViewRootImpl implements ViewParent {...}
    public interface ViewParent {...}
    

    上面的实现关系可以看出来ViewRootImpl并不是一个View, 他实际上是View的管理工具;

    class ViewRootImpl->
    @Override
    public void requestLayout() {
        if (!mHandlingLayoutInLayoutRequest) {
            mLayoutRequested = true;
            scheduleTraversals();
        }
    }
    void scheduleTraversals() {
        if (!mTraversalScheduled) {
            mTraversalScheduled = true;
            mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
            mChoreographer.postCallback(Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
        }
    }
    final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
    final class TraversalRunnable implements Runnable {
        @Override
        public void run() {
            doTraversal();
        }
    }
    void doTraversal() {
        if (mTraversalScheduled) {
            mTraversalScheduled = false;
            mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
            performTraversals();
        }
    }
    

    performTraversals()行数太多

    class ViewRootImpl->
    private void performTraversals() {
        if (mFirst || windowShouldResize || insetsChanged || viewVisibilityChanged || params != null || mForceNextWindowRelayout) {
            if (!mStopped || mReportNextDraw) {
                performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
            }
            if (didLayout) {
                performLayout(lp, mWidth, mHeight);
            }
            performDraw();
        }
    }
    

    1、三部曲->performMeasure:

    private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) {
        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "measure");
        try {
            mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
        } finally {
            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
        }
    }
    mView = DecorView;
    
    • 1、由前面代码知道mView其实是decorView;
    • 2、接下来是对decorView进行测量;
    public class DecorView extends FrameLayout {...}
    public class FrameLayout extends ViewGroup {...}
    public abstract class ViewGroup extends View implements ViewParent, ViewManager {...}
    public class View {...}
    

    上面继承关系, measure方法只有View方法中有:

    class View->
    public final void measure(int widthMeasureSpec, int heightMeasureSpec) {
        if (forceLayout || needsLayout) {
            int cacheIndex = forceLayout ? -1 : mMeasureCache.indexOfKey(key);
            if (cacheIndex < 0 || sIgnoreMeasureCache) {
                onMeasure(widthMeasureSpec, heightMeasureSpec);
            } 
        }
    }
    class FrameLayout->
    @Override
    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) {
                 measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0);
             }
        }
    }
    protected void measureChildWithMargins(View child, 
                                           int parentWidthMeasureSpec, int widthUsed,
                                           int parentHeightMeasureSpec, int heightUsed) {
        child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
    }
    

    上面代码做了下面几件事:

    • 1、调用DecorView中的measure方法, 该方法只在父类View中有
    • 2、所以调用View中的measure方法, 然后调用到里面的onMeasure()方法;
    • 3、而onMeasure()方法又只有父类FrameLayout中有, 所以执行FrameLayout方法中的onMeasure方法. 该方法会遍历子类, 然后依次调用子类的measure方法.

    1、三部曲->performLayout:

    class ViewRootImpl-->
    private void performLayout(WindowManager.LayoutParams lp, int desiredWindowWidth, int desiredWindowHeight) {
            final View host = mView;
            try {
                host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
            }
        }
    }
    mView = DecorView;
    class View-->
    @SuppressWarnings({"unchecked"})
    public void layout(int l, int t, int r, int b) {
        boolean changed = isLayoutModeOptical(mParent) ? setOpticalFrame(l, t, r, b) : setFrame(l, t, r, b);
        if (changed || (mPrivateFlags & PFLAG_LAYOUT_REQUIRED) == PFLAG_LAYOUT_REQUIRED) {
            onLayout(changed, l, t, r, b);
        }
    }
    class FrameLayout-->
    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        layoutChildren(left, top, right, bottom, false /* no force left gravity */);
    }
    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);
             if (child.getVisibility() != GONE) {
                 child.layout(childLeft, childTop, childLeft + width, childTop + height);
             }
        }
    }
    

    上面代码做了下面几件事:

    • 1、调用DecorView的layout方法, 实际上调用View的layout方法
    • 2、layout调用onLayout方法, onLayout方法被DecorView的父类FrameLayout方法重写, 实际调用FrameLayout的onLayout方法
    • 3、然后遍历DecorView里面的控件, 并对遍历的控件调用其layout方法;

    到此仅仅是把DecorView, 及其控件的绘制流程搞清楚了, 但是具体的实现细节并没有进行分析, 比如onMeasure和onLayout中大量出现的measureSize, measureMode这种数据的一系列计算全部跳过了, 这个步骤先留着吧, 后边如果有机会去在mac环境下一套源码, 调试着去分析, 不然真没法搞明白里面的道道儿

    相关文章

      网友评论

          本文标题:Android_窗口绘制相关流程

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