从源码看Activity生命周期

Activity是如何创建的

我们都知道在手机上点击应用的图标,系统会通过ActivityManagerService去启动它的主Activity,接下来我们就来一步步看看在它究竟是如何启动应用的。

首先手机开机的时候我们看到的界面其实是Launcher应用的主Activity,Launcher其实就是一个会被系统默认启动的安卓应用。在上面点击已装应用的图标,就会调用Actvity.startActivity去启动其他的应用。而Activity实际上是继承ContextWrapper的,所以调的是ContextWrapper.startActivity方法:

public class ContextWrapper extends Context {
     ...
     Context mBase;
     ...
     public ContextWrapper(Context base) {
         mBase = base;
     }
     ...
     @Override
     public void startActivity(Intent intent) {
         mBase.startActivity(intent);
     }
     ...
}

可以看到这里使用了委托的方式,实际上是调了mBase.startActivity。那这个mBase到底是什么呢?让我们来看看Context的继承关系图:

1.png

Context只有两个直接的子类,一个ContextImpl,一个ContextWrapper。ContextWrapper类如其名仅仅是一个包装的功能,它的成员变量mBase其实就是ContextImpl,所有实际的工作都是由ContextImpl去实现的。

于是我们就去看看ContextImpl.startActivity:

class ContextImpl extends Context {
    ...
    @Override
    public void startActivity(Intent intent) {
        ...
        startActivity(intent, null);
    }

    @Override
    public void startActivity(Intent intent, Bundle options) {
      ...
      mMainThread.getInstrumentation().execStartActivity(
                            getOuterContext(), mMainThread.getApplicationThread(), null,
                            (Activity)null, intent, -1, options);
    }
    ...
}

public final class ActivityThread {
    ...
    Instrumentation mInstrumentation;
    ...
    public Instrumentation getInstrumentation()  {
        return mInstrumentation;
    }
    ...
}

好吧,这里又将锅甩给了Instrumentation。Instrumentation其实也是一个比较偏但是很有作用的东西(通过它我们能做到很多神奇的事情,例如Hook 应用入口 Activity),主要用于监控Activity,这里我就不详细讲了,感兴趣的同学可以直接去搜索一下。我们直接看启动activity相关的代码:

public ActivityResult execStartActivity(
                Context who, IBinder contextThread, IBinder token, Activity target,
                Intent intent, int requestCode, Bundle options) {
   ...
   int result = ActivityManagerNative.getDefault()
                             .startActivity(whoThread, who.getBasePackageName(), intent,
                                          intent.resolveTypeIfNeeded(who.getContentResolver()),
                                          token, target != null ? target.mEmbeddedID : null,
                                          requestCode, 0, null, null, options);
   ...
}

这里的ActivityManagerNative最后拿到的就是ActivtyManagerService的IBinder,所以最后会使用Binder机制调用系统端的ActivityManagerService去创建Activity。

但是我们知道ActivityManagerService和我们的应用是在两个进程的,如果在ActivityManagerService中创建了Activity的话我们的应用也是获取不了的。

其实ActivityManagerService主要功能不是创建Activity,而是管理Activity栈。它在创建新的Activity的时候还是会通过Binder机制调回应用进程的ActivityThread去处理。最后ActivityManagerService只保存Activity的token。由于中间代码过于曲折,我这里就不贴出来了.这里直接看ActivityThread的代码吧:

public final class ActivityThread {
    final ArrayMap<IBinder, ActivityClientRecord> mActivities
                    = new ArrayMap<IBinder, ActivityClientRecord>();
    ...
    private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        ...
        Activity a = performLaunchActivity(r, customIntent);
        ...
    }
    ...
    private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        ...
        activity = mInstrumentation.newActivity(
                            cl, component.getClassName(), r.intent);
        ...
        r.activity = activity;
        ...
        mActivities.put(r.token, r);
    }
}

可以看到这里也是用Instrumentation去创建Activity的,创建完之后就将它丢到一个Map里面。而Instrumentation.newActivity则很简单,通过反射去创建Activity:

public class Instrumentation {
    ...
    public Activity newActivity(ClassLoader cl, String className, Intent intent)
                                throws InstantiationException, IllegalAccessException,
                                ClassNotFoundException {
        return (Activity)cl.loadClass(className).newInstance();
    }
    ...
}

总结下来,上面讲的的方法的调用时序图如下:

2.png

Activity的生命周期是如何被调用的

这里涉及到几个类:ActivityManagerService、ActivityStackSupervisor、ActivityStack、ActivityThread。

ActivityManagerService负责通过binder机制接收启动应用的请求,它内部有各个ActivityStackSupervisor成员变量,用于管理Activity栈:

public final class ActivityManagerService extends ActivityManagerNative
implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
    ...
    /** Run all ActivityStacks through this */
    ActivityStackSupervisor mStackSupervisor;
    ...
}

ActivityStackSupervisor管理用于Activity栈列表,它负责将Activity压入对应的Activity栈中:

public final class ActivityStackSupervisor {
    ...
    /** All the non-launcher stacks */
    private ArrayList<ActivityStack> mStacks = new ArrayList<ActivityStack>();
    ...
}

ActivityStack用于管理Activity的生命周期,例如在新Activity被压入的时候调用旧栈顶Activity的onPasuse和onStop还有新activity的onStart和onResume。

final class ActivityStack {
    ...
    final void startPausingLocked(boolean userLeaving, boolean uiSleeping) {
        ...
        prev.app.thread.schedulePauseActivity(prev.appToken, prev.finishing, userLeaving, prev.configChangeFlags);
        ...
    }
    ...
}

ActivityStack并不会直接调用Activity的生命周期方法,而是通过ActivityThread间接调用。由于ActivityStack在系统进程中,而ActivityThread在应用进程中,所以通过Binder机制调用之后去到ActivityThread那里不是主线程,于是ActivityThread内部就使用了Handler机制同步到主线程中调用:

public final class ActivityThread {
    ...
    public final void schedulePauseActivity(IBinder token, boolean finished,  boolean userLeaving, int configChanges) {
        queueOrSendMessage(
            finished ? H.PAUSE_ACTIVITY_FINISHING : H.PAUSE_ACTIVITY,
            token,
            (userLeaving ? 1 : 0),
            configChanges);
    }
    ...
    private void queueOrSendMessage(int what, Object obj, int arg1, int arg2) {
        synchronized (this) {
            Message msg = Message.obtain();
            msg.what = what;
            msg.obj = obj;
            msg.arg1 = arg1;
            msg.arg2 = arg2;
            mH.sendMessage(msg);
        }
    }
    ...
    private class H extends Handler {
        ...
        public void handleMessage(Message msg) {
            ...
            switch (msg.what) {
                ...
                case PAUSE_ACTIVITY:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityPause");
                    handlePauseActivity((IBinder)msg.obj, false, msg.arg1 != 0, msg.arg2);
                    maybeSnapshot();
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;
                ...
                case RESUME_ACTIVITY:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityResume");
                    handleResumeActivity((IBinder)msg.obj, true,
                    msg.arg1 != 0, true);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;
                ...
            }
            ...
        }
        ...
    }
    ...
    private void handlePauseActivity(IBinder token, boolean finished,boolean userLeaving, int configChanges) {
        ActivityClientRecord r = mActivities.get(token);
        ...
    }
}

这里需要提的一点是AcvitiyThread里面可能有不止一个activity。所以需要传一个token去指定调用哪个activity。handlePauseActivity方法最终会调用mInstrumentation.callActivityOnPause再调用到Activity.onPause。这里就不继续展示代码了。

总结一下,上面讲到的这些类之间的关系是这样的:

3.png

ActivityThread通过handler机制将activity的生命周期同步到主线程中调用:

4.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 151,511评论 1 330
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 64,495评论 1 273
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 101,595评论 0 225
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 42,558评论 0 190
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 50,715评论 3 270
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 39,672评论 1 192
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,112评论 2 291
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 29,837评论 0 181
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 33,417评论 0 228
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 29,928评论 2 232
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,316评论 1 242
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 27,773评论 2 234
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,253评论 3 220
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,827评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,440评论 0 180
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 34,523评论 2 249
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 34,583评论 2 249

推荐阅读更多精彩内容