从ActivityThread 到ViewRootImpl, View添加至界面全过程

来源:互联网 发布:java编写计算器的源码 编辑:程序博客网 时间:2024/05/16 06:45


首先我们要知道,Android程序的主入口是 ActivityThread 的 main函数中,所有应用程序 有且仅有一个ActivityThread.


        public static void main(String[] args) {//            .....//            .....            Looper.prepareMainLooper();            ActivityThread thread = new ActivityThread();            thread.attach(false);//            .......            Looper.loop();        }


上面省略了一部分代码,只看我们关注的即可.

可以看到,在main函数里, 为我们创建了个Looper. 并且new 了一个ActivityThread, 接着调用 ActivityThread 的attach(false) 方法.


private void attach(boolean system) {    .......    if(!system){  //非系统应用        final IActivityManager mgr = ActivityManagerNative.getDefault();        try {            mgr.attachApplication(mAppThread);        } catch (RemoteException ex) {            // Ignore        }    }}

可以看到,上面代码与 AmS(ActivityManagerService) 进行了关联. 这里有人就想了, 为什么要关联呢 ?

实际,由名字我们可以看出,AmS就是管理我们Activity的, 与之对应的还有 WmS(WindowManagerService)负责显示窗口到界面上,这里我们不讨论它..


 当我们启动APP时, AmS会 调用ApplicationThread的 bindApplication() 然后通过H (extends Handler)类  来传递给ActivityThread 的 handleBindApplicaiont().


public final void bindApplication(String processName, ApplicationInfo appInfo,        List<ProviderInfo> providers, ComponentName instrumentationName,        ProfilerInfo profilerInfo, Bundle instrumentationArgs,        IInstrumentationWatcher instrumentationWatcher,        IUiAutomationConnection instrumentationUiConnection, int debugMode,boolean enableOpenGlTrace, boolean isRestrictedBackupMode, boolean persistent,Configuration config, CompatibilityInfo compatInfo, Map<String, IBinder> services,        Bundle coreSettings) {    ..........    ..........    AppBindData data = new AppBindData();  //构建Application Data对象    data.processName = processName;    data.appInfo = appInfo;    data.providers = providers;    data.instrumentationName = instrumentationName;    data.instrumentationArgs = instrumentationArgs;    data.instrumentationWatcher = instrumentationWatcher;    data.instrumentationUiAutomationConnection = instrumentationUiConnection;    data.debugMode = debugMode;    data.enableOpenGlTrace = enableOpenGlTrace;    data.restrictedBackupMode = isRestrictedBackupMode;    data.persistent = persistent;    data.config = config;    data.compatInfo = compatInfo;    data.initProfilerInfo = profilerInfo;    sendMessage(H.BIND_APPLICATION, data);  //发送消息 至 ActivityThread.}

   
case BIND_APPLICATION:Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "bindApplication");AppBindData data = (AppBindData)msg.obj;handleBindApplication(data);Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);


接下来我们看 handleBindApplication(data)


private void handleBindApplication(AppBindData data) {    try {        //在这之前,data.info还是空值        data.info = getPackageInfoNoCheck(data.appInfo,data.compatInfo);        .......        Application app = data.info.makeApplication(data.restrictedBackupMode, null);    }}

可以看到, 这里调用到了 data.info.makeApplication(), 其内创建了ContextImpl 和 Application 我们来看代码~

public Application makeApplication(boolean forceDefaultAppClass,Instrumentation instrumentation) {    if (mApplication != null) {        return mApplication;    }    Application app = null;    try {        java.lang.ClassLoader cl = getClassLoader();  // 获取classLoader        .....        ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this); //创建ContextImpl        app = mActivityThread.mInstrumentation.newApplication(   //创建Application                cl, appClass, appContext);        appContext.setOuterContext(app);    } catch (Exception e) {        .......    }    ....    mApplication = app    if(instrumentation!=null){        instrumentation.callApplicationOnCreate(app);  //调用Application onCreate    }}



以上步骤就是创建Application的过程...

当我们要启动某个Activity时,  AmS会调用 scheduleLaunchActivity, 之后会通过 H 发送消息 至ActivityThread 调用 handleLaunchActivity.

public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,ActivityInfo info, Configuration curConfig, CompatibilityInfo compatInfo,        String referrer, IVoiceInteractor voiceInteractor, int procState, Bundle state,        PersistableBundle persistentState, List<ResultInfo> pendingResults,        List<ReferrerIntent> pendingNewIntents, boolean notResumed, boolean isForward,ProfilerInfo profilerInfo) {    .......    ActivityClientRecord r = new ActivityClientRecord();  // 构建记录Activity 信息类    //客户端activity,可以通过该token 通知AmS当前运行的Activity的状态.    r.token = token;    r.ident = ident;    r.intent = intent;    r.referrer = referrer;    r.voiceInteractor = voiceInteractor;    r.activityInfo = info;    r.compatInfo = compatInfo;    r.state = state;    r.persistentState = persistentState;    r.pendingResults = pendingResults;    r.pendingIntents = pendingNewIntents;    r.startsNotResumed = notResumed;    r.isForward = isForward;    r.profilerInfo = profilerInfo;    updatePendingConfiguration(curConfig);    sendMessage(H.LAUNCH_ACTIVITY, r);  //发送消息.}

发送消息后会调用 handleLaunchActivity,  在其内部, 会调用peformLaunchActivity,然后创建一个Activity.


private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {    .........    ........    Activity activity = null;    try {        java.lang.ClassLoader cl = r.packageInfo.getClassLoader();        activity = mInstrumentation.newActivity(  // newActivity                cl, component.getClassName(), r.intent);        StrictMode.incrementExpectedActivityCount(activity.getClass());        r.intent.setExtrasClassLoader(cl);        r.intent.prepareToEnterProcess();        if (r.state != null) {            r.state.setClassLoader(cl);        }    }}

可以看到这里利用了classLoader 来创建了一个Activity, 创建好Activity 之后 会调用到 Activity的attach方法,在attach方法内部进行一些 变量的赋值,并设置baseContext.


if (activity != null) {    Context appContext = createBaseContextForActivity(r, activity);    .....    .....    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的 performCreate方法,最终会调用 onCreate方法,然而我们在自己的 Activity里 重写到了onCreate.  有没有很熟悉的感觉~~~

接下来到我们自己 的onCreate中,一般我们都会在super.oncreate()后 写上setContentView(int layoutId).

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


这里调用了getWindow().setContentView(),   getWindow 返回的是mWindow, 然而mWindow实际是个PhoneWindow,它在activity.attach() 时 赋值. 我们直接去看PhoneWindow的 setContentView()方法.

@Overridepublic void setContentView(int layoutResID) {    // Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window    // decor, when theme attributes and the like are crystalized. Do not check the feature    // before this happens.    if (mContentParent == null) {        installDecor();    } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {        mContentParent.removeAllViews();    }    if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {        final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,                getContext());        transitionTo(newScene);    } else {        mLayoutInflater.inflate(layoutResID, mContentParent);    }    final Callback cb = getCallback();    if (cb != null && !isDestroyed()) {        cb.onContentChanged();    }}

 由上可以看到, 会进入installDecor方法 。


if (mDecor == null) {    mDecor = generateDecor();    mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);    mDecor.setIsRootNamespace(true);    if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {        mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);    }}if (mContentParent == null) {    mContentParent = generateLayout(mDecor);</span>    .......}

这里面主要是 generateDecor()方法 和 generateLayout方法.

generateDecor (); 内部创建一个DecorView,该类为 PhoneWindow内部类, 继承至FrameLayout,实际上 它就是我们的根布局. 在generateLayout内部, 会给decorview 加上一个修饰窗口,  修饰窗口可以理解为我们的标题栏, 之后会找到 id为ID_ANDROID_CONTENT 并强转成ViewGroup  该ViewGroup就是 mContentParent.

接下来回到setContentView 方法内,这时 mContentParent 被成功赋值.  接下来会调用mLayout.inflate(layoutResId,mContentParent), 将你自己的布局加入到mContenetParent中.

到此为止我们的窗口就填充完毕了,  接下来我们要去给显示出来.

当Activity准备完成后, 会通知AmS, 之后会进行一系列的调用, 最终调用到 Activity的makeVisible()方法. 添加就是从这里开始的.

void makeVisible() {    if (!mWindowAdded) {        ViewManager wm = getWindowManager();        wm.addView(mDecor, getWindow().getAttributes());        mWindowAdded = true;    }    mDecor.setVisibility(View.VISIBLE);}



可以看到 这里我们getWindowManager, 它返回的是Activity的 mWindowManager常亮,是在 attach方法内赋值的,而实现了WindowManager的 类是WindowManagerImpl, 但是WindowManagerImpl内部真正操作的类却是 WindowManagerGlobal.  So~  这里wm.addView 实际上是调用了 WindowManagerGlobal的addView, 下面我们来看看该方法.

 

    public void addView(View view, ViewGroup.LayoutParams params,                        Display display, Window parentWindow) {        // 检查参数有效性        if (view == null) {            throw new IllegalArgumentException("view must not be null");        }        if (display == null) {            throw new IllegalArgumentException("display must not be null");        }        if (!(params instanceof WindowManager.LayoutParams)) {            throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");        }        .......省略一些代码// 查看窗口类型数值 是否在 1000~ 1999之间, 这之间的值 都为子窗口,如果是则遍历找出该窗口的父窗口.</span>        if (wparams.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&                wparams.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {            final int count = mViews.size();            for (int i = 0; i < count; i++) {                if (mRoots.get(i).mWindow.asBinder() == wparams.token) {                    panelParentView = mViews.get(i);                }            }        }        // 构建ViewRootImpl        root = new ViewRootImpl(view.getContext(), display);        // view设置布局参数        view.setLayoutParams(wparams);        mViews.add(view);        mRoots.add(root);        mParams.add(wparams);</span>        // do this last because it fires off messages to start doing things        try {            //通过 root.setview view显示到手机窗口中.            root.setView(view, wparams, panelParentView);        }




可以看到 ,最后创建了ViewRootImpl, 并且给view设置参数, 并且把ViewRootImpl, view, wparams 分别加入三个集合中.  然后调用root,setView, 在setView内 最终会调用 res.mWindowSession.addToDisPlay()从而通知WmS加入该窗口.


以上,就是显示窗口的步骤.   

0 0
原创粉丝点击