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.流程图:


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和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的添加。

最后编辑于 :
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • Zygote是什么?有什么作用? Android系统底层基于Linux Kernel, 当Kernel启动过程会创...
    Mr槑阅读 2,930评论 4赞 18
  • 前言 Launcher启动app launcher就是android桌面应用程序。也是操作系统启动有第一个app。...
    第八区阅读 1,206评论 0赞 2
  • 还真是的。养它足足考验了我的耐心,就连这几天做梦,都会梦见它煤球一样的脸,围着我的脚,绕来绕去。 十几天了,就算是...
    宁黛阅读 216评论 0赞 1
  • 长城是由传奇影业、环球影业、中影、乐视影业等影业公司联合出品。据透露,传奇影业负责剧本开发、制片、投资;环球影业负...
    北城巷陌阅读 951评论 2赞 2
  • 文||胡思入梦菲 我想有所房子,不是面朝大海,却是春暖花开。房子不需要很大,也不用建在繁华的都市。 它可以在宁静的...
    丁渔阅读 400评论 7赞 8

友情链接更多精彩内容