Activity是什么时候显示出来的?

概要

在Android开发中,Activity可谓是最重要之一的组件了。分析和熟悉Activity的启动流程,可帮助认识整个Android系统全貌。这里主要分析基于Android7.0从startActivity到Activity页面显示这一过程。

1.涉及主要类:

android.app.Instrumentation.java 
android.app.ActivityThread.java
android.app.ActivityManager.java
com.android.server.am.ActivityManagerService.java
com.android.internal.policy.PhoneWindon.java
com.android.internal.policy.DecorView.java
android.view.WindowManage.java
com.android.server.wm.WindowManagerService.java

2.流程图:

《Activity是什么时候显示出来的?》 avtivity启动流程图.png

具体流程

1.Activity.startActivityForResult()
/**
 * @hide
 */
@Override
public void startActivityForResult(
        String who, Intent intent, int requestCode, @Nullable Bundle options) {
    ...
    Instrumentation.ActivityResult ar =
        mInstrumentation.execStartActivity(
            this, mMainThread.getApplicationThread(), mToken, who,
            intent, requestCode, options);
  ...
    }
    cancelInputsAndStartExitTransition(options);
}

首先我们看看这个mInstrumentation.execStartActivity(this, mMainThread.getApplicationThread(), mToken, who,intent, requestCode, options)这个方法。其中第二个参数是ActivityThread类中的内部类ApplicationThread,这个是IBinder的代理类,用户接收ActivityMangageService的消息。

2.Instrumentation.execStartActivity()
 public ActivityResult execStartActivity(
        Context who, IBinder contextThread, IBinder token, Activity target,
        Intent intent, int requestCode, Bundle options) {
      ...
    try {
        intent.migrateExtraStreamToClipData();
        intent.prepareToLeaveProcess(who);
        int result = ActivityManager.getService()
            .startActivity(whoThread, who.getBasePackageName(), intent,
                    intent.resolveTypeIfNeeded(who.getContentResolver()),
                    token, target != null ? target.mEmbeddedID : null,
                    requestCode, 0, null, options);
        checkStartActivityResult(result, intent);
    } catch (RemoteException e) {
        throw new RuntimeException("Failure from system", e);
    }
    return null;
}

这个方法主要通过IPC方式发送消息给AMS(指ActivityManageService.java(下同)),从而调用startActivity(),这里就涉及到AMS服务了,在这过程中会进行一系列的准备,其中保存判断被启动的的Activity所在的进程是否和当前Activity所在的进程一致,若不一致则会从zygote进程fork一个进程;还有比如Activity的启动方式的判断等。最终会通过Binder IPC调用ActivityThread.ApplicationThread中的scheduleLaunchActivity()方法

3.ActivityThread.ApplicationThread. scheduleLaunchActivity()

在这一步骤中会通过sendMessage(H.LAUNCH_ACTIVITY, r)发送消息给ActivityThread.H,从而调用handleLaunchActivity()方法;

4.ActivityThread.handleLaunchActivity()
  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);
      //省略部分代码
      }
}

这里主要看performLaunchActivity()这个方法,这个里面会创建Activity的实例,然后在调用Activity.attach()方法,之后调用Activity的一系列生命周期方法。

5.Activity.attach()
    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, ActivityConfigCallback activityConfigCallback) {
    attachBaseContext(context);

    mFragments.attachHost(null /*parent*/);

    mWindow = new PhoneWindow(this, window, activityConfigCallback);
    mWindow.setWindowControllerCallback(this);
    mWindow.setCallback(this);
    mWindow.setOnWindowDismissedCallback(this);
    mWindow.getLayoutInflater().setPrivateFactory(this);
    if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
        mWindow.setSoftInputMode(info.softInputMode);
    }
    if (info.uiOptions != 0) {
        mWindow.setUiOptions(info.uiOptions);
    }
    //省略部分代码
}

这个方法参数比较多,我们主要看下对应的Window的创建:通过代码我们可以看到只要调用attach方法就会创建一个对应的window,也就是说一个Activity对应一个window(window只有个实现类就是PhoneWindow)。PhoneWindow创建的同时又会创建DecorView(相当于是Activity的rootView)。

    public class DecorView extends FrameLayout implements RootViewSurfaceTaker, WindowCallbacks 

DecorView继承与FrameLayout,查看PhoneWindow.java源码你会发现会DecorView添加两个子View:R.id.title和com.android.internal.R.id.content。到这里就可以知道Activity和Window的关系了:

《Activity是什么时候显示出来的?》 activity和window关系图.png

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

执行完attach之后紧接着会调用Activity中的相关生命周期方法onCreate()、onStart()和onResume()方法。之后就会执行上面的makeVisible()方法,这里才是真正的开始绘制显示Activity视图。在这个方法中会调用windowManage添加window,最终会通过ViewRootImpl.java这个类的setView(),然后在通过Binder IPC和WindowManageService通信最终完成window的添加。
这里有个问题:当我们每次去更新UI的时候都是通过ViewRootImpl去执行更新以及检查当前执行更新的线程。而ViewRootImpl的创建就是在执行wm.addView()的时候创建的。所以在ViewRootImpl没有创建之前是不会对线程进程检查及更新绘制UI的。

总结

通过对Activity的启动过程及视图的呈现分析,我们可以总结如下:

1、通过Binder IPC的方式和AMS通信完成Activity创建前的一系列准备。若要启动的这个Activity所在的进程没有启动,那么AMS会通过Socket发送消息给Zygote,Zygote会fork出应用程序进程,并且通过反射创建这个应用程序的ActivityThread,并且调用ActivityThread的main方法,此时这个应用程序就启动了;

2、在AMS完成准备工作之后又以IPC的方式发送lunchActivity消息,ActivityThread.ApplicationThreah 收到消息之后,又通过handler机制发送LAUNCH_ACTIVITY消息给ActivityThread.H;

3、之后通过Instrumentation.newActivity()完成Activity的创建;

( Activity activity = (Activity)clazz.newInstance())

4、在创建完Activity实例之后会调用Activity.acctch()方法完成window和DecorView的创建,最终通过WindowManage.addView()完成对window的添加。

    原文作者:YouJZ
    原文地址: https://www.jianshu.com/p/7106540197bb
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞