当前位置:   article > 正文

Activity的启动流程详解_am strat启动activity

am strat启动activity

简介


踏入Android开发有一小段时间了,第一次接手项目的时候状态就是上午自己写Bug,下午改自己的Bug,慢慢的接触的技术多了,就开始写项目上的一些小模块之类的,作为一个开发,技术是永远都学不完的,技术的更新速度快过自己的学习速度,但是个人觉得,如果想作为一名合格的程序猿,一些开发 的底层代码是肯定要了解的。就打个比方(就拿Android来说),你如果是实习的时候去面试,面试官问你Activity的启动流程是怎样的,你脑子里第一反应就是onCreate,onStrat,onResume,onPause,onStop,onDestory。但是如果你是有两三年工作经验的程序猿,面试官问你Activity的具体启动流程是怎样的,如果你还是回答如上的话,那不好意思,你可以回家等消息了。所以说,不管做什么技术开发都好,一些底层的代码还是需要去了解的,这对你提升自身技术的速度有很大的帮助…废话就不多说,开始进入今天的话题…


Activity启动流程初了解


当你点击手机桌面的一个App图标的时候,App是怎么知道要打开哪个界面,是谁通知这个App要启动的,这就离不开AMS的存在了,带着这些疑问,接着往下看…

首先,在手机屏幕上点击App的图标,此时的手机屏幕就是一个Activity,而这个Activity所在的App,在Android业界中称之为Launcher,Launcher是各个手机系统厂商提供的,主要的不同就是一些动画效果以及人性化设计。
然后,我们在开发App的时候,每创建一个Activity都要在AndroidManifest.xml文件里面注册这个Activity,这是因为当你安装这个App的时候,PMS(PackageManagerService)会把这个Apk包里面的AndroidManifest.xml文件里面所有信息都读取并且保存下来,以便后续的使用。
最后,以斗鱼为例,斗鱼和Launcher是两个不同的App,他们两个存在于不同的进程之中,Launcher要启动斗鱼App,这就少不了这两个进程之间的相互通信了,Android中通信最常用的也是最好用的无非就是Binder了,没了解过Binder的同学可以看看这篇文章Android Binder之间的相互通信

当你启动斗鱼App的时候,主要大致经过如下7个流程:

  1. Launcher首先会去通知AMS,告诉AMS要启动斗鱼App,而且会具体到启动斗鱼App的哪个页面(也就是首页);
  2. AMS回应Launcher,“好了我(AMS)知道了,没你(Launcher)啥事了”,同时也会把要启动的首页的信息记录下来,以便后续使用;
  3. 之后Launcher就开始进入休眠状态,然后告诉AMS,我(Launcher)进入休眠了,剩下的事情交给你(AMS)了;
  4. AMS首先回去检查斗鱼App有没有启动,有的话直接唤起即可,没有的话就要先启动一个新的进程,ASM会在新的进程之中创建一个ActivityThread对象,启动其中的main函数,然后启动斗鱼App;
  5. 斗鱼App启动之后,会告诉AMS,“我(斗鱼App)启动好了”;
  6. AMS然后会把步骤2中保存的信息取出来,告诉斗鱼APP具体要启动哪个界面;
  7. 斗鱼App启动首页,创建Context并与首页Activity关联,然后调用首页Activity的onCreate函数;

这些步骤只是从Launcher中启动一个App,接下来我们接着说一个Activity是如何从开始启动到onCreate函数之间的流程。

想必也都知道Java的程序入口就是main()方法,也就是上文我们步骤4中提到的main函数,看看源码

public static void main(String[] args){
    ...
    //初始化Looper
    Looper.prepareMainLooper(); 
    //实例化一个ActivityThread
    ActivityThread thread = new ActivityThread();
    //这个方法最后就是为了发送出创建Application的消息
    thread.attach(false);
    //主线程进入无限循环状态,等待接收消息
    Looper.loop();
    ...
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

这里比较关键的就是attach方法,attach()方法最终的目的是发送出一条创建Application的消息——H.BIND_APPLICATION,到主线程的主Handler中,告知要初始化Application

public void attach(boolean system){
    ...
    //获得IActivityManager实例,下面会看看它是个啥
    final IActivityManager mgr = ActivityManagerNative.getDefault();  
    try {
        mgr.attachApplication(mAppThread);
    } catch (RemoteException ex) {
        throw ex.rethrowFromSystemServer();
    }
    ...
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

这里出现了IActivityManager,它其实是一个接口,当调用ActivityManagerNative.getDefault()的时候,我们可以得到ActivityManagerProxy,ActivityManagerProxy是一个代理类的实例,也是ActivityManagerNative的一个内部类,然而ActivityManagerProxy的构造函数需要一个IBinder参数,然后进行一个赋值操作

public ActivityManagerProxy(IBinder remote) {
        mRemote = remote;
}
  • 1
  • 2
  • 3

调用这个AMP构造函数的地方如下:

static public IActivityManager asInterface(IBinder obj) {
    if (obj == null) {
        return null;
    }
    //先检查一下本地有木有,有的话直接取
    IActivityManager in = (IActivityManager)obj.queryLocalInterface(descriptor);
   
    if (in != null) {
        return in;
    }
    ...
    //没有就New一个新的
    return new ActivityManagerProxy(obj);
 
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

然后返回ActivityManagerNative.getDefault()来,我们来看看getDefault()获取到的静态常量gDefault的源码:

private static final Singleton<IActivityManager> gDefault = 
  new Singleton<IActivityManager>() {
    protected IActivityManager create() {
        //在这里就获得了上文需要的IBinder实例
        IBinder b = ServiceManager.getService("activity");
        ...
        IActivityManager am = asInterface(b);
        ...
        return am;
    }
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

这里是通过ServiceManager获取到IBinder实例的,获取IBinder的目的就是为了通过这个IBinder和ActivityManager进行通讯,进而ActivityManager会调度发送H.BIND_APPLICATION即初始化Application的Message消息,既然拿到了IBinder,那我们接着看attachApplication(mAppThread)这个方法中的mAppThread,在ActivityThread的成员变量中,你可以看到:

final ApplicationThread mAppThread = new ApplicationThread();
  • 1

mAppThread是ActivityThread和AMS交互的中间桥梁,ApplicationThread是ActivityThread中的一个内部类,继承自ApplicationThreadNative,巧了,ApplicationThreadNative继承自Binder

public abstract class ApplicationThreadNative extends Binder 
    implements IApplicationThread{
    ...
    public ApplicationThreadNative() {
        attachInterface(this, descriptor);
    }
    ...
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

那么很明显,ApplicationThread最终也是一个Binder,所以说mAppThread是ActivityThread和AMS交互的中间桥梁,经过上面的辗转,ApplicationThread终于到了ActivityManagerService中了。
接着我们看下AMS里面的其中一个方法:

private final boolean attachApplicationLocked(IApplicationThread thread, int pid) {
    ...
    //此处省去N行代码
    thread.bindApplication();
    ...
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

经过一系列的操作,最终被调用了自己的bindApplication()方法,发出初始化Applicationd的消息,在bindApplication()方法里有这样一行代码:

 sendMessage(H.BIND_APPLICATION, data);
  • 1

发出创建Application的消息,一旦接收到这个消息就开始创建Application了,这个过程是在handleBindApplication()中完成的。

private void handleBindApplication(AppBindData data) {
    ...
    //通过反射初始化一个Instrumentation仪表(后续会单独出一篇相关文章来介绍)。
    //Instrumentation会在应用程序的任何代码运行之前被实例化,它能够允许你监视应用程序和系统的所有交互
    mInstrumentation = (Instrumentation) cl.loadClass(data.instrumentationName.getClassName()).newInstance();
    ...
    //通过LoadedApp命令创建Application实例
    Application app = data.info.makeApplication(data.restrictedBackupMode, null);
    ...
    mInitialApplication = app;
    ...
    //让仪器调用Application的onCreate()方法
    mInstrumentation.callApplicationOnCreate(app);

    ...
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

最后调用了callApplicationOnCreate()方法,就创建了Application,当Application初始化完成后,系统会从AndoridManifest中的配置启动Activity发送一个Intent去启动相应的Activity,当H收到LAUNCH_ACTIVITY消息后便开始执行创建Activity,处理消息的源码如下:

private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
    ...
    Activity a = performLaunchActivity(r, customIntent);

    ...
    if (a != null) {
        ...
        //Activity创建成功就执行onResume()
        handleResumeActivity(r.token, false
        , r.isForward
        ,!r.activity.mFinished && !r.startsNotResumed
        , r.lastProcessedSeq, reason);
  
        ...
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

performLaunchActivity方法中,挑选了几行重要的代码如下所示:

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    ...
    //通过仪表来创建Activity
    activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);
    ...
    //获取Application
    Application app = r.packageInfo.makeApplication(false, mInstrumentation);
    ...
    //根据是否可持久化选择Activity的onCreate()方法
    if (r.isPersistable()) {
        mInstrumentation.callActivityOnCreate(
          activity, r.state, r.persistentState);
    } else {
        mInstrumentation.callActivityOnCreate(activity, r.state);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

在newActivity里面就反射实例化Activity,没有别的了,然后根据是否可持久化选择Activity的onCreate()方法,到此,Activity就创建好了,同学们细品哈,如有不足之处请多多指教~

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/AllinToyou/article/detail/528858
推荐阅读
相关标签
  

闽ICP备14008679号