会让您对通晓Android绘制有赞助,由它来担负实行所在进度的主线程新闻循环处理澳门永利娱乐总站


前言

在此以前大约分析了setContentView的三个履行流程,可是我们依旧不知道我们的布局是怎么添加到Activity窗口在那之中的,要消除那么些难题,大家务必从Activity运营的源码入手。

阅读者三篇Android绘制小说,会让您对了然Android绘制有帮带:

流程分析

  • ActivityThread.java

    public static void main(String[] args) {
     // 代码省略
        Looper.prepareMainLooper();
        ActivityThread thread = new ActivityThread();
        thread.attach(false);
        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }
        Looper.loop();
    }

成百上千一度从事Java,以往从业Android的人都惊奇为啥Android没有main方法,其实是有些。通过翻阅有关文书档案,大家驾驭ActivityThread是应用程序真真的入口,每一个应用程序有且唯有多个ActivityThread,由它来担负实行所在进度的主线程新闻循环处理。在ActivityThread的main方法中,咱们看看它早先化了主线程handler,开启了新闻循环,那么它的handler里面循环处理什么工作呢?

  • ActivityThread.java

public void handleMessage(Message msg) {
            switch (msg.what) {
                case LAUNCH_ACTIVITY: {
                    handleLaunchActivity(r, null);
                } break;
// 代码省略...
}

private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
// 代码省略...
    Activity a = performLaunchActivity(r, customIntent);
    if (a != null) {
        r.createdConfig = new Configuration(mConfiguration);
        Bundle oldState = r.state;
        handleResumeActivity(r.token, false, r.isForward,
                !r.activity.mFinished && !r.startsNotResumed);
                }
 // 代码省略...
}

handleMessage里面处理的事情基本上是与第四次全国代表大会组件相关,比如敞开暂停甘休3个Activity或Service等,那里大家只用关切LAUNCH_ACTIVITY,看看它在那之中做了何等。

大家发未来LAUNCH_ACTIVITY里面,它调用了handleLaunchActivity,而handleLaunchActivity里面又调用了handleResumeActivity。

  • ActivityThread.java

    final void handleResumeActivity(IBinder token,
        // 代码省略
        ActivityClientRecord r = performResumeActivity(token, clearHide);
                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();
                decor.setVisibility(View.INVISIBLE);
                ViewManager wm = a.getWindowManager();
                WindowManager.LayoutParams l = r.window.getAttributes();
                a.mDecor = decor;
                l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
                l.softInputMode |= forwardBit;
                if (a.mVisibleFromClient) {
                    a.mWindowAdded = true;
                    wm.addView(decor, l);
                }
        }

            // 代码省略

在handleResumeActivity里面,首先是由此调用performResumeActivity方法取得了当前Activity的标识(ActivityClientRecord持有当前Activity以及有关的种种状态新闻),然后再来获取当前Activity关联的Window对象以及WindowManager对象,最后将DecorView添加到WindowManager中。那么WindowManager中是怎么落到实处的吗?

  • WindowManager.java

public interface WindowManager extends ViewManager {
//代码省略
}

能够窥见,WindowManager只是3个接口,那么它的贯彻类在怎么地点吧,从handleResumeActivity方法中大家得以看出,WindowManager是因此Activity获取的,所以我们照旧要从Activity的代码中去摸索它的兑现类。

  • ActivityThread.java

    private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {

//代码省略
                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);

//代码省略
                activity.mCalled = false;
                if (r.isPersistable()) {
                    mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
                } else {
                    mInstrumentation.callActivityOnCreate(activity, r.state);
                }
//代码省略
        return activity;
    }
  • Activity.java

public class Activity extends ContextThemeWrapper
        implements LayoutInflater.Factory2,
        Window.Callback, KeyEvent.Callback,
        OnCreateContextMenuListener, ComponentCallbacks2,
        Window.OnWindowDismissedCallback {

public WindowManager getWindowManager() {
    return mWindowManager;
}

final void attach(Context context, ActivityThread aThread..)

  //省略
    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();
    mCurrentConfig = config;
}

}
  • Window.java

    public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
            boolean hardwareAccelerated) {
        mAppToken = appToken;
        mAppName = appName;
        mHardwareAccelerated = hardwareAccelerated
                || SystemProperties.getBoolean(PROPERTY_HARDWARE_UI, false);
        if (wm == null) {
            wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
        }
        mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
    }

小编们领略,当2个Activity运营,会调用ActivityThread的performLaunchActivity,然后在performLaunchActivity里面会率先调用Activity的attach方法,再调用onCreate方法。而在Activity的attach方法里面能够看看,Activity的WindowManager对象实际是出自于Window,而Window的setWindowManager方法里面揭露出WindowManager的落到实处类是WindowManagerImpl。

  • WindowManagerImpl.java

    private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();

    @Override
    public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
        applyDefaultToken(params);
        mGlobal.addView(view, params, mDisplay, mParentWindow);
    }
  • WindowManagerGlobal.java

    public void addView(View view, ViewGroup.LayoutParams params,
            Display display, Window parentWindow) {
//代码省略
        ViewRootImpl root;
        View panelParentView = null;
            }
            if (wparams.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
                    wparams.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
//代码省略
            root = new ViewRootImpl(view.getContext(), display);
            view.setLayoutParams(wparams);
            mViews.add(view);
            mRoots.add(root);
            mParams.add(wparams);
        }
        root.setView(view, wparams, panelParentView);
//代码省略

*ViewRootImpl.java

    public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
        //代码省略
                requestLayout();  // 调用View的绘制
                if ((mWindowAttributes.inputFeatures
                        & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
                    mInputChannel = new InputChannel();
                }
                try {
                    mOrigWindowType = mWindowAttributes.type;
                    mAttachInfo.mRecomputeGlobalAttributes = true;
                    collectViewAttributes();
                    // 最终的添加显示
                    res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                            getHostVisibility(), mDisplay.getDisplayId(),
                            mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                            mAttachInfo.mOutsets, mInputChannel);
                } 
        }

在WindowManagerImpl的addView方法中,我们发现它又是调用的WindowManagerGlobal的addView方法,而在WindowManagerGlobal的addView方法中,通过层层传递,它会把DecorView传递给ViewRootImpl的setView,然后在ViewRootImpl中展开最终的绘图工作。

在ViewRootImpl中,有2个地方要求我们注意,一个是requestLayout()方法,3个是mWindowSession.addToDisplay方法,mWindowSession是系统服务WindowManagerService在应用程序中开创的代理对象,它说到底会因而Binder跨进程调用WindowManager瑟维斯的addWindow()方法,然后扩充窗口界面。

而requestLayout()方法里面则是开展具体界面绘制的要害措施。

*ViewRootImpl.java

    @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();
    }
}

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);

         if (mProfile) {
             Debug.startMethodTracing("ViewAncestor");
         }

         performTraversals();

         if (mProfile) {
             Debug.stopMethodTracing();
             mProfile = false;
         }
     }
 }

  //真正执行UI绘制的遍历过程

private void performTraversals() {
// 代码省略
    performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
    performLayout(lp, desiredWindowWidth, desiredWindowHeight);
    performDraw();
  }

在requestLayout里面调用了scheduleTraversals()方法,在scheduleTraversals()方法里面开启了一个称为TraversalRunnable的线程进行实施遍历,而在进行遍历的doTraversal()方法里面,它说到底调用了performTraversals()方法,这些办法是终极的界面绘制的方法,那个点子其实是调用了DecorView的measure、layout、draw方法进行View树绘制遍历。

总结

最后大家来总括下布局添加到Activity窗口的实际流程。

澳门永利娱乐总站 1

0BF668A9-A6EB-4B65-BC6B-2FFB2C6AF3A0.png


① 、Activity窗口构成

此处大家会介绍到ActivityPhoneWindowDecorViewViewRootImplWindowManagerImplWindowManagerGlobalActivityThreadSurface,关于Activity窗口有好多上边可讲,小编这边只侧重于Activity窗口的Render方面来上课。先来两张张大家早已经烂熟于心的图:

1-1 Activity起步流程图

1-2 Activity构成图

叁个Activity的结缘有,ActivityPhoneWindowDecorView,再加上DecorView里面包车型客车TitleBar和大家填充的content内容,那一个还Activity构成供给的具体类,不是局地协助类,其实还有ViewRootImplWindowManagerImplWindowManagerGlobalActivityThread那几个不可知的扶助类,尽管是Activity构成可见UI界面没用到,可是那多少个支持类都是向来可能直接承担了Activity的营造和制图的。上边作者依据笔者的通晓来挨家挨户介绍这么些类的作用和被创制时机,有畸形的地方还请咱们指正:

  • Activity:二个继承ContextThemeWrapper的类,继承自ContextThemeWrapper那么意味着,通过Activity能够访问当前包的财富(getResources、getAssets)和运营别的零件(Activity、Service、布罗兹cast)以及获得各样服务(getSystemService),并且定义了脚下Activity的Theme核心项目
    ,关于Context的解释请看:http://www.cnblogs.com/android100/p/Android-Context.html
    与此同时唯有创制了3个Activity才会创制前边的PhoneWindow、DecorView、ViewRootImpl、WindowManagerImpl、和Surface那么些类。笔者那里并没说ActivityThread类,ActivityThread是Android应用的主线程(UI线程),多个选择进度才有3个UI线程。也从不说WindowManagerGlobal类,那个类用了多少个数组管理三个运用进度内全部Activity的DecorView和ViewRootImpl以及WindowManager对应涉及的。WindowManagerGlobal是叁个单例的类,一个应用进度内也唯有3个。可是WindowManagerImpl是每三个Activity都有多个的。Activity是在ActivityThread的performLaunchActivity方法中用ClassLoader类加载器创立出来的。

  • PhoneWindow:
    1个继续于肤浅类Window的类,也是Window的唯一兑现类。在Activity中PhoneWindow处在一级地方,可是PhoneWindow是一个不可知的类,PhoneWindow内的DecorView才是我们看得出的UI布局,但是大家看得出的UI布局为啥要卷入一层PhoneWindow列?经过本身的反复查看源代码和商量,我发现PhoneWindow担当了Activity
    UI界面拔尖布局DecorView的创办,PhoneWindow保存了window
    attributes即窗口布局属性参数,保存了与WindowManagerService进程通信的IBinder
    (取名token)方便去系统WindowManagerService进度通信,并且负责了用户Key和Touch事件的散发,但是PhoneWindow分发事件也是提交了DecorView来形成的。除了我们Activity在setContent时PhoneWindow创制了DecorView,好像PhoneWindow并不曾担当太多的Render的轩然大波。看源码确实正是这么啊!,其实确实的Render操作都在ViewRootImpl类中。PhoneWindow是在Activity的attach方法中new出来的。

  • WindowManagerImpl:
    见名知意,就是管理Window的,在那里便是管理PhoneWindow的,每一个Activity都有四个谈得来的WindowManagerImpl来保管自身的PhoneWindow,WindowManagerImpl其实是用来管理PhoneWindow里面包车型大巴DecorView的,也或者是DecorView级别的任何的View,还有正是WindowManagerImpl是用来跟2个App全局的PhoneWindow管理器WindowManagerGlobal通信的,添加、移除和立异DecorView层级的View时WindowManagerImpl会调用WindowManagerGlobal中的方法来进行全局管理。WindowManagerImpl是在Activity的attach方法中new
    PhoneWindow后调用mWindow.setWindowManager方法成立的,其里面是调用setWindowManager的createLocalWindowManager方法new出来的。

  • DecorView:
    是2个ViewGroup,继承自FrameLayout,是大家看看的UI界面包车型地铁一流容器,DecorView是PhoneWindow的成员。DecorView除了那些之外是Activity界面包车型大巴头等容器以外,DecorView照旧key和touch事件从上向下真正分发起首的源头。事件分发从Activity—》PhoneWindow—》DecorView—》层层向下分发到大家的界面底层。DecorView其实在诸多地点都会创建,PhoneWindow内部的getDecorView方法被调用时,若是在那之中的成员变量mDecor为空的话,就会调用installDecor()方法去创设三个DecorView,最终new
    2个DecorView再次来到,保证调用PhoneWindow的getDecorView获取
    DecorView时世代不会为空。
    本人看代码发现PhoneWindow的DecorView第三次调用爆发在ActivityThread内的handleResumeActivity方法中,handleResumeActivity方法中还有一个很重要的步子,正是调用了WindowManagerImpl的addView(DecorView,WindowManager.LayoutParams
    )方法,进去成立了三个跟DecorView关联的ViewRootImpl类。

  • ViewRootImpl:是一个落到实处了ViewParent接口的final类。小编眼下说到了,ViewRootImpl重若是肩负Activity的界面Render绘制的,负责整个窗口界面的ViewTree的绘图更新。ViewRootImpl要承担DecorView的绘图,那么ViewRootImpl就须要全体当前Activity的DecorView的引用,是的,的确如此,后边介绍DecorView的创设的时候本人说到了DecorView第一回成立发生在ActivityThread内的handleResumeActivity方法中,handleResumeActivity方法中还有2个很关键的步子,就是调用了WindowManagerImpl的addView(DecorView,WindowManager.LayoutParams
    )方法,进去成立了三个跟DecorView关联的ViewRootImpl类。WindowManagerImpl的addView方法其实调用了WindowManagerGlobal的addView方法,在那个方法中开创了ViewRootImpl,并且在那几个法子中调用了ViewRootImpl的setView方法,使ViewRootImpl持有DecorView的引用。并且把贯彻了ViewParent接口的亲善设置成了DecorView的Parent。那样ViewRootImpl就足以盛气凌人地操作DecorView了。其实作者在调用普通view的invalidate()刷新时,其实是透过层层Parent寻找,最终调用了最顶层的ParentViewRootImpl的invalidate()来判断和拍卖每一次的UI界面刷新的。

  • Surface:三个落到实处了Parcelable接口的类,对Parcelable接口不掌握的,请看作者事先的Binder通信的稿子:Android
    IPC之AIDL看这一篇还不够
    Surface是固有图像缓冲区(raw
    buffer)的3个句柄,而本来图像缓冲区是由显示屏图像合成器(screen
    compositor)管理的。得到了Surface那么些句柄就能够赢得在那之中的Canvas、原生缓冲器以及别的地点的情节。所以说Surface是生成Canvas的地点,具体就是调用lockCanvas方法赢得Canvas。至于Canvas、Paint
    和Bitmap的涉及作者那里就不讲了,后面会有成文来讲那些。Surface是ViewRootImpl的二个final成员变量,伴随ViewRootImpl的开创私下认可就new三个出去了,可是此时的Surface是2个空的,里面是没有内容的。Surface的数额填充是要跟WindowManagerService相互的,应用进程端Binder公告WindowManagerService进度端创制二个Surface对象,最终是将WindowManagerService进度端的
    Surface对象传递到利用进度端并赋值给采取进程的Surface对象,那样窗口能够利用Surface来绘制UI了。
    因为Surface对象要夸进程传递,所以Surface要达成Parcelable接口。更详尽的介绍有关窗口的Surface创造请看老罗的:Android应用程序窗口(Activity)的绘图表面(Surface)的制程分析

贰 、Activity窗口创设流程

地方的名词介绍其实正是比照窗口的创始流程的相继来讲的,不过单单是文字不够直观,上面以箭头加方法名的款型表现一下,源码分析流程基于Android7.1

/**1*/ ApplicationThread的onTransact方法接收到SystemServer进程的SCHEDULE_LAUNCH_ACTIVITY_TRANSACTION启动Activity的Binder信息
                ↓
/**2*/ ApplicationThread.scheduleLaunchActivity() //
                ↓
/**3*/ ActivityThread.scheduleLaunchActivity() //安排启动Activity
                ↓
/**4*/ ActivityThread.handleLaunchActivity()  //处理启动Activity
                ↓
/**5*/ ActivityThread.handleResumeActivity() // Activity 的Resume会使DecorView跟ViewRootImpl关联
                ↓
/**6*/ WindowManagerGlobal.addView() //全局保存窗口的信息
                ↓
/**7*/ ViewRootImpl.setView()  //使DecorView和ViewRootImpl关联并绘制界面
                ↓
/**8*/ ViewRootImpl.requestLayout() //请求绘制ViewTree
                ↓
/**9*/ ViewRootImpl.scheduleTraversals() // 安排遍历 
                ↓
/**10*/ ViewRootImpl.doTraversal() //
                ↓
/**11*/ ViewRootImpl.performTraversals() //执行遍历 会根据情况调用relayoutWindow performMeasure performLayout performDraw 等方法 这四个方法跟绘制是紧密相关的
                ↓
/**12*/ ViewRootImpl.relayoutWindow() //窗口第一次创建或者是窗口大小有变化并且窗口可见就会调用此方法 
                ↓
/**13*/ ViewRootImpl.mWindowSession.relayout() //binder通信通知WindowManagerService创建一个跟应用端关联的Surface
                ↓
/**14*/ ViewRootImpl调用performMeasure performLayout performDraw方法绘制UI

实则第六步ActivityThread.handleResumeActivity()方法内会调用到WindowManagerGlobal.addView()方法把窗口绘制完毕,紧接着就调用到了activity.makeVisible()方法,其实正是呈现出DecorView,因为DecorView创造绘制前是被设置成了INVISIBLE的,Activity中的makeVisible方法正是把绘制完结的DecorView突显出来了:

    void makeVisible() {
        if (!mWindowAdded) {
            ViewManager wm = getWindowManager();
            wm.addView(mDecor, getWindow().getAttributes());
            mWindowAdded = true;
        }
        mDecor.setVisibility(View.VISIBLE); //把DecorView设置成可见的
    }

从那之后我们就观察Activity界面上的UI了。

至于Activity的绘图表面(Surface)的创制进程本人还想多说一下,以及Surface跟Activity的对应关系。

Surface是ViewRootImpl的叁个final成员变量,伴随ViewRootImpl的创制暗中认可就new三个出去了,可是此时的Surface是五个空的,里面是从未有过内容的。Surface的数据填充是要跟WindowManagerService互动的,应用进程端Binder文告WindowManagerService进度端创立3个Surface对象,最终是将WindowManagerService进度端的
Surface对象传递到使用进度端并赋值给采纳进度的Surface对象,这样窗口能够动用Surface来绘制UI了。
因为Surface对象要夸进度传递,所以Surface要贯彻Parcelable接口。

从Activity窗口创设的流水线我们可以明白:

  • 每二个应用程序窗口都对相应多少个Java层的Surface对象,当中3个是在WindowManagerService劳务那旁边创建的,而除此以外二个是在应用程序进度那旁边创制的。

  • 在WindowManagerService服务那旁边开立的Java层的Surface对象在C++层关联有多少个SurfaceControl目的,用来安装使用窗口的属性,例如,大小和任务等。

  • 在应用程序进程那旁边成立的ava层的Surface指标在C++层关联有一个Surface对象,用来绘制应用程序窗品的UI。

三 、Activity窗口组件之间的相应关系

2个设施有3个WindowManagerService进程 有一个SystemServer进程

一个App有一个WindowManagerGlobal类 有一个ActivityThread类
有一个ApplicationThread类

一个App能够有无数个Activity

一个 Activity有一个PhoneWindow类

一个PhoneWindow类有一个ViewRootImpl类

一个PhoneWindow类有一个WindowManagerImpl类

一个ViewRootImpl类有一个Surface类 有一个DecorView类

用一张图表示:

Android设备构成图

参考作品:
Android应用程序窗口(Activity)的绘图表面(Surface)的创设进度分析
从源码看invalidate和requestLayout的不一致
Android
Render连串规划篇

Android应用层View绘制流程与源码分析

相关文章