Activity 的啟動過程

一、前言:

通常我們在Activity中啟動一個另一個Activity,就是調(diào)用Activity的startActivity方法,這個最終會調(diào)用到Activity的startActivityForResult方法。那你有沒有想過Activity的啟動到底經(jīng)歷了哪些過程蟀瞧,我們今天就來分析一下沉颂。

在具體分析之前,要先說明一下悦污,Activity的啟動流程在細(xì)節(jié)挺繁瑣的铸屉,比如啟動另一個App的Activity或者啟動不同的launchMode的Activity,在細(xì)節(jié)上都會有不同切端。我們這次的源碼分析著重分析一下流程彻坛,為了簡單起見,就以分析一個Activity啟動app內(nèi)部另一個standard模式的Activity為主踏枣。

Activity啟動另一個Activity之前昌屉,當(dāng)前的Activity先要執(zhí)行onPause,被啟動的Activity才會執(zhí)行到onResume方法椰于。這中間實(shí)際上是會執(zhí)行4次IPC過程的:

  • 當(dāng)前Activity發(fā)起啟動另一個Activity的請求——>ActivityManagerService
  • ActivityManagerService——> 通知App暫停當(dāng)前Activity
  • 當(dāng)前App告知已經(jīng)暫停了當(dāng)前的Activity——> ActivityManagerService
  • ActivityManagerService ——> 通知App啟動新的Activity

注:本次源碼分析采用Android7.0怠益,不同版本的源碼在細(xì)節(jié)上會有不同仪搔,比如瘾婿,在Android8.0上ActivityManagerService就改成了以AIDL的方式來寫,請不要太糾結(jié)API的不同烤咧。

二偏陪、Activity啟動涉及到的類

首先要簡單介紹一下Activity啟動過程涉及到的類,以便于更好的理解這個啟動過程煮嫌。

  • ActivityThread:App啟動的入口
  • ApplicationThread:ActivityThread的內(nèi)部類笛谦,繼承Binder,可以進(jìn)程跨進(jìn)程通信昌阿。
  • ApplicationThreadProxy:ApplicationThread的一個本地代理饥脑,其它的client端通過這個對象調(diào)用server端ApplicationThread中方法。
  • Instrumentation:負(fù)責(zé)發(fā)起Activity的啟動懦冰、并具體負(fù)責(zé)Activity的創(chuàng)建以及Activity生命周期的回調(diào)灶轰。一個應(yīng)用進(jìn)程只會有一個Instrumentation對象,App內(nèi)的所有Activity都持有該對象的引用刷钢。
  • ActivityManagerService:簡稱AMS笋颤,是service端對象,負(fù)責(zé)管理系統(tǒng)中所有的Activity
  • ActivityManagerProxy:是ActivityManagerService的本地代理
  • ActivityStack:Activity在AMS的棧管理内地,用來記錄已經(jīng)啟動的Activity的先后關(guān)系伴澄,狀態(tài)信息等。通過ActivityStack決定是否需要啟動新的進(jìn)程阱缓。
  • ActivityRecord:ActivityStack的管理對象非凌,每個Activity在AMS對應(yīng)一個ActivityRecord,來記錄Activity的狀態(tài)以及其他的管理信息荆针。其實(shí)就是服務(wù)器端的Activity對象的映像敞嗡。
  • TaskRecord:AMS抽象出來的一個“任務(wù)”的概念并蝗,是記錄ActivityRecord的棧,一個“Task”包含若干個ActivityRecord秸妥。AMS用TaskRecord確保Activity啟動和退出的順序滚停。

介紹完這些,我們開始進(jìn)入正題

三粥惧、Activity的啟動過程

Activity啟動最終會調(diào)用到startActivityForResult方法键畴,我們只需要關(guān)注mParent == null中的邏輯即可。mParent代表的是ActivityGroup突雪,其最開始是為了在一個界面中嵌入多個子Activity起惕,在API13的時候就已經(jīng)廢棄了,可以使用Fragment表示一個界面的多個區(qū)域咏删。

# android.app.Activity
public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
                                   @Nullable Bundle options) {
    if (mParent == null) {
        Instrumentation.ActivityResult ar =
                mInstrumentation.execStartActivity(
                        this, mMainThread.getApplicationThread(), mToken, this,
                        intent, requestCode, options);
        if (ar != null) {
            mMainThread.sendActivityResult(
                    mToken, mEmbeddedID, requestCode, ar.getResultCode(),
                    ar.getResultData());
        }
        ...
    } else {
        ...
    }
}

調(diào)用了Instrumentation的execStartActivity方法惹想,在這里通過ActivityManagerNative.getDefault()方法獲取ActivityManagerService的一個本地代理對象ActivityManagerProxy,然后調(diào)用了其startActivity方法:

# android.app.Instrumentation
public ActivityResult execStartActivity(
        Context who, IBinder contextThread, IBinder token, Activity target,
        Intent intent, int requestCode, Bundle options) {
    IApplicationThread whoThread = (IApplicationThread) contextThread;
    ...
    try {
       ... 
        int result = ActivityManagerNative.getDefault()
                .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;
}

我們看一下ActivityManagerNative督函,繼承了Binder并實(shí)現(xiàn)了IActivityManager接口嘀粱,ActivityManagerService就是繼承了ActivityManagerNative。

public abstract class ActivityManagerNative extends Binder implements IActivityManager
public final class ActivityManagerService extends ActivityManagerNative implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback
class ActivityManagerProxy implements IActivityManager

ActivityManagerNative實(shí)際上獲取的就是其內(nèi)部類ActivityManagerProxy對象辰狡。ActivityManagerProxy只是ActivityManagerService的本地代理對象锋叨,其startActivity方法會調(diào)用到AMS的startActivity方法。而且要注意宛篇,這個startActivity方法會把ApplicationThread對象傳遞到AMS所在進(jìn)程娃磺,當(dāng)然了AMS拿到的實(shí)際上是ApplicationThread的代理對象ApplicationThreadProxy,AMS就要通過這個代理對象與我們的App進(jìn)程進(jìn)行通信叫倍。

# android.app.ActivityManagerNative
private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
    protected IActivityManager create() {
        IBinder b = ServiceManager.getService("activity");
        if (false) {
            Log.v("ActivityManager", "default service binder = " + b);
        }
        IActivityManager am = asInterface(b);
        if (false) {
            Log.v("ActivityManager", "default service = " + am);
        }
        return am;
    }
};

static public IActivityManager asInterface(IBinder obj) {
    if (obj == null) {
        return null;
    }
    IActivityManager in =
            (IActivityManager)obj.queryLocalInterface(descriptor);
    if (in != null) {
        return in;
    }

    return new ActivityManagerProxy(obj);
}

static public IActivityManager getDefault() {
    return gDefault.get();
}

注:在Android8.0偷卧,由于使用AIDL的方式來寫ActivityManagerService,ActivityManagerNative已經(jīng)過期吆倦。

我們接著看一下AMS的startActivity方法:

# com.android.server.am.ActivityManagerService
public final int startActivity(IApplicationThread caller, String callingPackage,
                               Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
                               int startFlags, ProfilerInfo profilerInfo, Bundle bOptions) {
    return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
            resultWho, requestCode, startFlags, profilerInfo, bOptions,
            UserHandle.getCallingUserId());
}

startActivity方法緊接著調(diào)用了其startActivityAsUser方法听诸。

@Override
public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
                                     Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
                                     int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId) {
    enforceNotIsolatedCaller("startActivity");
    userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
            userId, false, ALLOW_FULL_ONLY, "startActivity", null);
    // TODO: Switch to user app stacks here.
    return mActivityStarter.startActivityMayWait(caller, -1, callingPackage, intent,
            resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
            profilerInfo, null, null, bOptions, false, userId, null, null);
}

接著調(diào)用了ActivityStarter的startActivityMayWait方法,由于方法很長逼庞,我們只保留關(guān)鍵的流程部分:

# com.android.server.am.ActivityStarter
final int startActivityMayWait(IApplicationThread caller, int callingUid,
        String callingPackage, Intent intent, String resolvedType,
        IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
        IBinder resultTo, String resultWho, int requestCode, int startFlags,
        ProfilerInfo profilerInfo, IActivityManager.WaitResult outResult, Configuration config,
        Bundle bOptions, boolean ignoreTargetSecurity, int userId,
        IActivityContainer iContainer, TaskRecord inTask) {
   
        ...
        int res = startActivityLocked(caller, intent, ephemeralIntent, resolvedType,
                aInfo, rInfo, voiceSession, voiceInteractor,
                resultTo, resultWho, requestCode, callingPid,
                callingUid, callingPackage, realCallingPid, realCallingUid, startFlags,
                options, ignoreTargetSecurity, componentSpecified, outRecord, container,
                inTask);

         ...
    }
}

ActivityStarter調(diào)用了自身的startActivityLocked方法蛇更,這又是一個很長的方法,保留關(guān)鍵的流程如下赛糟。

# com.android.server.am.ActivityStarter

final int startActivityLocked(IApplicationThread caller, Intent intent, Intent ephemeralIntent,
        String resolvedType, ActivityInfo aInfo, ResolveInfo rInfo,
        IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
        IBinder resultTo, String resultWho, int requestCode, int callingPid, int callingUid,
        String callingPackage, int realCallingPid, int realCallingUid, int startFlags,
        ActivityOptions options, boolean ignoreTargetSecurity, boolean componentSpecified,
        ActivityRecord[] outActivity, ActivityStackSupervisor.ActivityContainer container,
        TaskRecord inTask) {
    int err = ActivityManager.START_SUCCESS;
    ...
    try {
        mService.mWindowManager.deferSurfaceLayout();
        err = startActivityUnchecked(r, sourceRecord, voiceSession, voiceInteractor, startFlags,
                true, options, inTask);
    } finally {
        mService.mWindowManager.continueSurfaceLayout();
    }
    postStartActivityUncheckedProcessing(r, err, stack.mStackId, mSourceRecord, mTargetStack);
    return err;
}

ActivityStarter又調(diào)用了自身的startActivityUnchecked方法派任,

# com.android.server.am.ActivityStarter

private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
        IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
        int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask) {
    ...
    if (mDoResume) {
        ...
        if (!mTargetStack.isFocusable()
            ...
        } else {
            mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity,
                    mOptions);
        }
    } else {
       ...
    }
    ...
    return START_SUCCESS;
}

在ActivityStarter中調(diào)用了ActivityStackSupervisor的resumeFocusedStackTopActivityLocked方法。

# com.android.server.am.ActivityStackSupervisor

boolean resumeFocusedStackTopActivityLocked(
        ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) {
    if (targetStack != null && isFocusedStack(targetStack)) {
        return targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);
    }
    ... 
}

在ActivityStackSupervisor的resumeFocusedStackTopActivityLocked中又調(diào)用了ActivityStack的resumeTopActivityUncheckedLocked方法璧南。

# com.android.server.am.ActivityStack

boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) {
   ...
    boolean result = false;
    try {
        // Protect against recursion.
        mStackSupervisor.inResumeTopActivity = true;
        ...
        result = resumeTopActivityInnerLocked(prev, options);
    } finally {
        mStackSupervisor.inResumeTopActivity = false;
    }
    return result;
}

ActivityStack在resumeTopActivityUncheckedLocked又調(diào)用了其自身的resumeTopActivityInnerLocked方法掌逛。

# com.android.server.am.ActivityStack
private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
     ..
    // We need to start pausing the current activity so the top one can be resumed...
    ...
    if (mResumedActivity != null) {
        if (DEBUG_STATES) Slog.d(TAG_STATES,
                "resumeTopActivityLocked: Pausing " + mResumedActivity);
        pausing |= startPausingLocked(userLeaving, false, next, dontWaitForPause);
    }
    ...
}

由于當(dāng)前的Activity執(zhí)行了onResume,所以mResumedActivity != null 條件滿足司倚,就會調(diào)用startPausingLocked方法先暫停當(dāng)前的Activity豆混。注意:這個過程必然是一個IPC過程篓像。我們看一下startPausingLocked方法。

# com.android.server.am.ActivityStack
final boolean startPausingLocked(boolean userLeaving, boolean uiSleeping,
        ActivityRecord resuming, boolean dontWait) {

    ActivityRecord prev = mResumedActivity;
    ...

    if (prev.app != null && prev.app.thread != null) {
        if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Enqueueing pending pause: " + prev);
        try {
            ...
            prev.app.thread.schedulePauseActivity(prev.appToken, prev.finishing,
                    userLeaving, prev.configChangeFlags, dontWait);
        } catch (Exception e) {
           ...
        }
    } else {
       ...
    }
    ...
}

prev.app.thread表示的是IApplicationThread對象皿伺,在這里就是指的發(fā)起啟動的Activity所在進(jìn)程的ApplicationThread的本地代理ApplicationThreadProxy员辩。調(diào)用它的schedulePauseActivity方法,很明顯是一次IPC過程鸵鸥,最終調(diào)用到server端奠滑,也就是發(fā)起啟動的Activity所在進(jìn)程ApplicationThread的schedulePauseActivity方法。

# android.app.ActivityThread$$ApplicationThread

public final void schedulePauseActivity(IBinder token, boolean finished,
        boolean userLeaving, int configChanges, boolean dontReport) {
    int seq = getLifecycleSeq();
    if (DEBUG_ORDER) Slog.d(TAG, "pauseActivity " + ActivityThread.this
            + " operation received seq: " + seq);
    sendMessage(
            finished ? H.PAUSE_ACTIVITY_FINISHING : H.PAUSE_ACTIVITY,
            token,
            (userLeaving ? USER_LEAVING : 0) | (dontReport ? DONT_REPORT : 0),
            configChanges,
            seq);
}

通過Hander的轉(zhuǎn)發(fā)妒穴,接著會調(diào)用到ActivityThread的handlePauseActivity方法宋税。

# android.app.ActivityThread

private void handlePauseActivity(IBinder token, boolean finished,
        boolean userLeaving, int configChanges, boolean dontReport, int seq) {
    ActivityClientRecord r = mActivities.get(token);
    ...
    if (r != null) {
    ...
        performPauseActivity(token, finished, r.isPreHoneycomb(), "handlePauseActivity");
    ...
        // Tell the activity manager we have paused.
        if (!dontReport) {
            try {
                ActivityManagerNative.getDefault().activityPaused(token);
            } catch (RemoteException ex) {
                throw ex.rethrowFromSystemServer();
            }
        }
        mSomeActivitiesChanged = true;
    }
}

在ActivityThread的handlePauseActivity中,首先會調(diào)用performPauseActivity來暫停當(dāng)前的Activity讼油,經(jīng)過層層調(diào)用杰赛,會調(diào)用到Intrumentation的callActivityOnPause方法,最終調(diào)用Activity的onPause方法矮台,這一塊的流程比較簡單乏屯,在這里就不再詳細(xì)分析了,感興趣的可以自己研究下嘿架。
暫停之后瓶珊,會調(diào)動ActivityManagerNative.getDefault().activityPaused(token)啸箫,這個很明顯又是一次IPC過程耸彪,就是告訴AMS,已經(jīng)暫停當(dāng)前的Activity忘苛,可以啟動新的Activity 了蝉娜。
我們來看一下AMS的的activityPaused方法:

# com.android.server.am.ActivityManagerService
@Override
public final void activityPaused(IBinder token) {
    final long origId = Binder.clearCallingIdentity();
    synchronized(this) {
        ActivityStack stack = ActivityRecord.getStackLocked(token);
        if (stack != null) {
            stack.activityPausedLocked(token, false);
        }
    }
    Binder.restoreCallingIdentity(origId);
}

AMS中的activityPaused又調(diào)用了ActivityStack的activityPausedLocked方法。

# com.android.server.am.ActivityStack

final void activityPausedLocked(IBinder token, boolean timeout) {
    ...
    final ActivityRecord r = isInStackLocked(token);
    if (r != null) {
        mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
        if (mPausingActivity == r) {
            if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to PAUSED: " + r
                    + (timeout ? " (due to timeout)" : " (pause complete)"));
            completePauseLocked(true, null);
            return;
        } else {
           ...
        }
    }
   ...
}

在這個方法中又調(diào)用了ActivityStack自身的completePauseLocked方法扎唾,

# com.android.server.am.ActivityStack
private void completePauseLocked(boolean resumeNext, ActivityRecord resuming) {
    ActivityRecord prev = mPausingActivity;
    if (resumeNext) {
        final ActivityStack topStack = mStackSupervisor.getFocusedStack();
        if (!mService.isSleepingOrShuttingDownLocked()) {
            mStackSupervisor.resumeFocusedStackTopActivityLocked(topStack, prev, null);
        } else {
           ...
        }
    }
    ...
}

然后又調(diào)用了ActivityStackSupervisor的resumeFocusedStackTopActivityLocked方法召川,這視乎又重新調(diào)用了一遍,真復(fù)雜啊胸遇。
這個流程我們上面講過了荧呐,ActivityStackSupervisor會繼續(xù)調(diào)用ActivityStack的resumeTopActivityUncheckedLocked方法,然后ActivityStack又調(diào)用其resumeTopActivityInnerLocked方法纸镊,調(diào)來調(diào)去倍阐,又到這個方法里面了,上次在這里是執(zhí)行了前一個Activity的onPause方法逗威。這次會調(diào)用到ActivityStackSupersivor的startSpecificActivityLocked方法峰搪。

# com.android.server.am.ActivityStack
private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
    
    // We need to start pausing the current activity so the top one can be resumed...
    final boolean dontWaitForPause = (next.info.flags & FLAG_RESUME_WHILE_PAUSING) != 0;
    boolean pausing = mStackSupervisor.pauseBackStacks(userLeaving, next, dontWaitForPause);
    if (mResumedActivity != null) {
        if (DEBUG_STATES) Slog.d(TAG_STATES,
                "resumeTopActivityLocked: Pausing " + mResumedActivity);
        pausing |= startPausingLocked(userLeaving, false, next, dontWaitForPause);
    }

    ...
    ActivityStack lastStack = mStackSupervisor.getLastStack();
    if (next.app != null && next.app.thread != null) {
        ...
    } else {
        ...
        mStackSupervisor.startSpecificActivityLocked(next, true, true);
    }

    if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
    return true;
}

分析到這里,好像我們的就要開始啟動我們的目標(biāo)Activity了凯旭,好激動有木有概耻!
在ActivityStackSupersivor的startSpecificActivityLocked方法中會判斷Activity所在進(jìn)程是否存在使套,如果不存在的話就要創(chuàng)建一個新的進(jìn)程。在這里鞠柄,我們是Activity啟動其App內(nèi)部的另一個Activity侦高,所以進(jìn)程肯定是存在的,會走到realStartActivityLocked方法中厌杜。

# com.android.server.am.ActivityStackSupervisor
void startSpecificActivityLocked(ActivityRecord r,
        boolean andResume, boolean checkConfig) {
    ... 
    if (app != null && app.thread != null) {
        try {
    ...
            realStartActivityLocked(r, app, andResume, checkConfig);
            return;
        } catch (RemoteException e) {
           ...
        }

    }

    mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
            "activity", r.intent.getComponent(), false, false, true);
}

再來看一下ActivityStackSupersivor的realStartActivityLocked方法矫膨,這次似乎真的要啟動一個Activity了。

# com.android.server.am.ActivityStackSupervisor

final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app,
        boolean andResume, boolean checkConfig) throws RemoteException {
    ...
    try {

        app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
                System.identityHashCode(r), r.info, new Configuration(mService.mConfiguration),
                new Configuration(task.mOverrideConfig), r.compat, r.launchedFromPackage,
                task.voiceInteractor, app.repProcState, r.icicle, r.persistentState, results,
                newIntents, !andResume, mService.isNextTransitionForward(), profilerInfo);
       ...

    } catch (RemoteException e) {
       ...
    }
    ...
    return true;
}

看了代碼期奔,果然侧馅,調(diào)用了app.thread.scheduleLaunchActivity方法,app.thread我們前面講過呐萌,就是IApplicationThread對象馁痴,實(shí)際上就是ApplicationThreadProxy對象,經(jīng)過IPC過程會調(diào)用到ApplicationThread的scheduleLaunchActivity方法肺孤,我們來看一下:

# android.app.ActivityThread$$ApplicationThread
@Override
public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
        ActivityInfo info, Configuration curConfig, Configuration overrideConfig,
        CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor,
        int procState, Bundle state, PersistableBundle persistentState,
        List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
        boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) {

    ...
    sendMessage(H.LAUNCH_ACTIVITY, r);
}

通過Hander的轉(zhuǎn)發(fā)罗晕,接著會調(diào)用到ActivityThread的handlePauseActivity方法。

# android.app.ActivityThread
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);
      ...
    } else {
       ...
    }
}

handlePauseActivity內(nèi)部調(diào)用performLaunchActivity方法:

# android.app.ActivityThread
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    ...
    Activity activity = null;
    try {
        java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
        activity = mInstrumentation.newActivity(
                cl, component.getClassName(), r.intent);
        ...
    } catch (Exception e) {
       ...
    }

    try {
        Application app = r.packageInfo.makeApplication(false, mInstrumentation);
        ...
        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, window);

            ...
            activity.mCalled = false;
            if (r.isPersistable()) {
                mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
            } else {
                mInstrumentation.callActivityOnCreate(activity, r.state);
            }
           ...
            r.activity = activity;
            r.stopped = true;
            if (!r.activity.mFinished) {
                activity.performStart();
                r.stopped = false;
            }
            if (!r.activity.mFinished) {
                if (r.isPersistable()) {
                    if (r.state != null || r.persistentState != null) {
                        mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state,
                                r.persistentState);
                    }
                } else if (r.state != null) {
                    mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state);
                }
            }
            if (!r.activity.mFinished) {
                activity.mCalled = false;
                if (r.isPersistable()) {
                    mInstrumentation.callActivityOnPostCreate(activity, r.state,
                            r.persistentState);
                } else {
                    mInstrumentation.callActivityOnPostCreate(activity, r.state);
                }
                if (!activity.mCalled) {
                    throw new SuperNotCalledException(
                        "Activity " + r.intent.getComponent().toShortString() +
                        " did not call through to super.onPostCreate()");
                }
            }
        }
        r.paused = true;

        mActivities.put(r.token, r);

    } catch (SuperNotCalledException e) {
        throw e;

    } catch (Exception e) {
       ...
    }

    return activity;
}

在performLaunchActivity內(nèi)部赠堵,創(chuàng)建了Activity對象小渊,并調(diào)用了activity的attach方法,在這個方法中綁定一些屬性茫叭,并且創(chuàng)建了Activity所屬的Window對象酬屉。接著Instrumentation會調(diào)用callActivityOnCreate、callActivityOnRestoreInstanceState揍愁、callActivityOnPostCreate等來完成Activity生命周期的回調(diào)呐萨。不過有一點(diǎn)很有意思,在這個方法中Activity自己調(diào)用了其performStart方法莽囤,但這個方法內(nèi)部又調(diào)用了Instrumentation的callActivityOnStart方法谬擦,進(jìn)而又調(diào)用了Activity的onStart方法。繞過來繞過去朽缎,總之惨远,Activity生命周期方法的調(diào)用均是通過Instrumentation來控制的。

至此话肖,Activity的啟動過程算是分析完了北秽,太費(fèi)腦筋了,需要來一瓶營養(yǎng)快線補(bǔ)補(bǔ)身體狼牺。流程太多羡儿,不好記,但是有句話說的好 "一圖勝千言"是钥,下面我們來看一下Activity啟動的一個時序圖掠归。

圖片.png

四缅叠、總結(jié):

源碼分析過程是比較繞,比較燒腦的過程虏冻,不要太糾結(jié)去API的調(diào)用肤粱,盡量側(cè)重流程。分析源碼厨相,最好帶著問題去分析领曼,不要為了分析而分析,盡量在分析過程中尋找自己想要的答案蛮穿。比如:

1庶骄、Activity對象是怎么創(chuàng)建的?

  • Activity 對象是在應(yīng)用程序啟動時由 Android 系統(tǒng)創(chuàng)建的践磅。當(dāng)用戶啟動應(yīng)用程序并點(diǎn)擊應(yīng)用程序圖標(biāo)時单刁,系統(tǒng)會為其創(chuàng)建一個新的進(jìn)程,并在其中創(chuàng)建主 Activity府适。
  • 具體來說羔飞,在 AndroidManifest.xml 文件中配置的啟動 Activity 將作為應(yīng)用程序的入口點(diǎn),并成為該進(jìn)程的第一個組件檐春。系統(tǒng)會自動實(shí)例化該 Activity 并調(diào)用其 onCreate() 方法逻淌,該方法用于初始化該 Activity 的狀態(tài)和資源。
  • 在后續(xù)的生命周期中疟暖,Activity 對象會根據(jù)需要動態(tài)創(chuàng)建或銷毀卡儒。例如,當(dāng)用戶從一個 Activity 轉(zhuǎn)到另一個 Activity 時誓篱,系統(tǒng)會銷毀前一個 Activity朋贬,并創(chuàng)建新的 Activity。當(dāng)應(yīng)用程序被關(guān)閉時窜骄,系統(tǒng)會依次銷毀所有的 Activity,并釋放相關(guān)資源摆屯。
  • 需要注意的是邻遏,在某些情況下,您可以通過使用 Intent 或 startActivityForResult() 等機(jī)制來啟動其他應(yīng)用程序的 Activity虐骑。在這種情況下准验,與該 Activity 相關(guān)聯(lián)的生命周期和資源管理由該應(yīng)用程序負(fù)責(zé),而不是你的應(yīng)用程序廷没。

2糊饱、Window對象是什么時候創(chuàng)建的?

  • Window 對象是在 Activity 被創(chuàng)建時由 Android 系統(tǒng)自動創(chuàng)建的颠黎。在 Activity 的生命周期中另锋,Window 對象的創(chuàng)建和銷毀與 Activity 的創(chuàng)建和銷毀密切相關(guān)滞项。
  • 具體而言,在 Activity 的 onCreate() 方法中夭坪,系統(tǒng)會調(diào)用 Activity 的 getWindow() 方法來獲取該 Activity 的 Window 對象文判,并將其作為返回值返回。這個 Window 對象用于顯示該 Activity 的用戶界面和管理與用戶交互的事件室梅。
  • 一個 Activity 可以擁有多個 Window 對象戏仓,但通常情況下只會有一個主要的 Window 對象,用于顯示 Activity 的內(nèi)容亡鼠。如果需要顯示額外的窗口(如對話框或彈出菜單等)赏殃,則可以通過調(diào)用 Dialog 類或 PopupWindow 類的構(gòu)造函數(shù)來創(chuàng)建它們的 Window 對象。
  • 需要注意的是间涵,與大多數(shù) Android 組件一樣嗓奢,Window 對象也有其自己的生命周期。當(dāng) Activity 被銷毀時浑厚,與之關(guān)聯(lián)的 Window 對象也會被銷毀股耽,并釋放相關(guān)資源。因此钳幅,應(yīng)該避免在 Activity 被銷毀后繼續(xù)使用其 Window 對象物蝙,以避免出現(xiàn)異常或內(nèi)存泄漏等問題敢艰。

3诬乞、LayoutInflater什么時候創(chuàng)建的?

  • LayoutInflater 是在 Activity 運(yùn)行期間動態(tài)創(chuàng)建的钠导。當(dāng) Activity 調(diào)用 setContentView() 方法時震嫉,系統(tǒng)會使用 LayoutInflater 對布局文件進(jìn)行解析,并將其轉(zhuǎn)換為 View 對象牡属。
  • 在調(diào)用 setContentView() 方法時票堵,系統(tǒng)會自動創(chuàng)建一個 LayoutInflater 對象。這個 LayoutInflater 對象通常是由該 Activity 的 Context 對象創(chuàng)建的逮栅,因此它可以訪問應(yīng)用程序的資源和服務(wù)悴势。
  • LayoutInflater 在解析布局文件時使用了緩存機(jī)制,以提高性能并避免重復(fù)的解析過程措伐。一旦布局文件被解析并轉(zhuǎn)換為 View 對象特纤,就不需要再次解析了。如果您需要對同一布局文件進(jìn)行多次解析侥加,則可以使用 LayoutInflater 的 cloneInContext() 方法來創(chuàng)建一個新的 LayoutInflater 對象捧存,并將其與另一個 Context 關(guān)聯(lián)起來,以避免影響原始的 LayoutInflater 緩存。
  • 需要注意的是,LayoutInflater 只能用于解析布局文件,它不能直接用于創(chuàng)建 View 對象昏翰。如果您需要在代碼中動態(tài)創(chuàng)建 View 對象,則可以使用 View 或其子類的構(gòu)造函數(shù)進(jìn)行創(chuàng)建朋魔。

4、為什么在Activity中的布局中或者Fragment的中View獲取的- Context都是其所在的Activity對象卿操?

  • 在 Android 中警检,每個 View 都必須與一個 Context 對象相關(guān)聯(lián)。這個 Context 對象通常是其所在的 Activity 或 Fragment 的 Context害淤。
  • 當(dāng)布局文件中的 View 被加載到 Activity 或 Fragment 中時扇雕,它們會自動繼承其父級的 Context 對象。因此窥摄,在 Activity 或 Fragment 中訪問 View 時镶奉,它們將返回其所在的 Activity 或 Fragment 對象作為 Context。
  • 這也意味著崭放,如果您在自定義 View 中需要使用 Context 對象哨苛,最好的方法是將其傳遞給構(gòu)造函數(shù)并保存為成員變量,而不是直接從 View 中獲取 Context币砂。這樣可以確保您的 View 在任何上下文中都能正常工作建峭,并且可以避免潛在的內(nèi)存泄漏問題。
  • 需要注意的是决摧,在使用 Context 對象時要小心亿蒸,特別是在涉及到生命周期或資源管理方面的操作時。在不需要使用 Context 對象時掌桩,應(yīng)該盡可能地避免持有它边锁,以免導(dǎo)致內(nèi)存泄漏或其他問題。

4波岛、為什么自定義View一定要有兩個參數(shù)的構(gòu)造函數(shù)茅坛?

在 Android 中,自定義 View 必須有兩個參數(shù)的構(gòu)造函數(shù)盆色,即:

public CustomView(Context context, AttributeSet attrs)

這是因?yàn)樵诓季治募新暶髯远x View 時灰蛙,系統(tǒng)會自動調(diào)用該構(gòu)造函數(shù)來創(chuàng)建 View 的實(shí)例,并將布局文件中定義的屬性傳遞給該實(shí)例隔躲。

  • 第一個參數(shù) context 表示上下文,用于獲取資源和訪問系統(tǒng)服務(wù)物延。
  • 第二個參數(shù) attrs 則表示包含了布局文件中定義的所有屬性的值的 AttributeSet 對象宣旱。

如果您不重寫這個構(gòu)造函數(shù),那么當(dāng)您在布局文件中使用自定義 View 時叛薯,系統(tǒng)將無法正確地解析它所定義的屬性浑吟,從而導(dǎo)致出現(xiàn)運(yùn)行時錯誤笙纤。

需要注意的是,自定義 View 構(gòu)造函數(shù)的第二個參數(shù) AttributeSet 并不是必須的组力。如果您的自定義 View 不需要使用 XML 屬性省容,可以只提供一個參數(shù)的構(gòu)造函數(shù)。但是燎字,為了保持一致性腥椒,建議始終實(shí)現(xiàn)兩個參數(shù)的構(gòu)造函數(shù)。

5候衍、Activity的生命周期方法是被誰回調(diào)的笼蛛?

Activity 的生命周期方法是被 Android 系統(tǒng)回調(diào)的。當(dāng) Activity 發(fā)生狀態(tài)改變時蛉鹿,例如創(chuàng)建滨砍、啟動、停止或銷毀等妖异,系統(tǒng)會自動調(diào)用對應(yīng)的生命周期方法惋戏。

下面是 Activity 常用的生命周期方法及其描述:

  • onCreate():當(dāng) Activity 第一次被創(chuàng)建時調(diào)用。
  • onStart():當(dāng) Activity 可見但未獲得焦點(diǎn)時調(diào)用他膳。
  • onResume():當(dāng) Activity 可見并且獲得焦點(diǎn)時調(diào)用响逢。
  • onPause():當(dāng) Activity 失去焦點(diǎn)但仍然可見時調(diào)用。
  • onStop():當(dāng) Activity 不再可見時調(diào)用矩乐。
  • onDestroy():當(dāng) Activity 被銷毀時調(diào)用龄句。

除了上述方法之外,還有一些其他的生命周期方法散罕,如 onRestart()分歇、onSaveInstanceState() 和 onRestoreInstanceState() 等,它們在特定情況下被調(diào)用欧漱。這些方法的調(diào)用順序也是固定的职抡,并且可以通過重寫這些方法來控制 Activity 的行為和狀態(tài)。

6误甚、Application是什么時候創(chuàng)建的缚甩?

在 Android 應(yīng)用程序的生命周期中,Application 對象是在應(yīng)用程序啟動時由系統(tǒng)創(chuàng)建的窑邦。當(dāng)用戶第一次啟動應(yīng)用程序時擅威,系統(tǒng)會為其創(chuàng)建一個進(jìn)程并開始執(zhí)行應(yīng)用程序的代碼。

  • 在該進(jìn)程中冈钦,Application 對象是第一個被創(chuàng)建的組件郊丛,它負(fù)責(zé)管理應(yīng)用程序的全局狀態(tài)和資源。在 Application 對象被創(chuàng)建之前,任何其他組件(如 Activity)都不能被創(chuàng)建厉熟。
  • 一旦 Application 對象被創(chuàng)建导盅,它將一直存在于整個應(yīng)用程序的生命周期中,直到應(yīng)用程序被終止揍瑟。因此白翻,我們可以利用 Application 對象來保存應(yīng)用程序中需要在多個組件之間共享的數(shù)據(jù),以及初始化全局的資源和服務(wù)等绢片。

需要注意的是滤馍,Application 對象是運(yùn)行在主線程上的,因此應(yīng)該避免在 Application 對象中執(zhí)行長時間運(yùn)行的操作杉畜,否則可能會導(dǎo)致應(yīng)用程序無響應(yīng)甚至崩潰纪蜒。

7、ClassLoader對象是什么時候創(chuàng)建的此叠?

ClassLoader 對象在 Java 程序運(yùn)行期間動態(tài)創(chuàng)建纯续,用于加載類文件。ClassLoader 是在需要加載類時動態(tài)創(chuàng)建的灭袁,可以根據(jù)不同的需求創(chuàng)建不同的 ClassLoader 實(shí)例猬错。

在 Java 應(yīng)用程序啟動時,會默認(rèn)創(chuàng)建三個 ClassLoader 對象:

  • Bootstarp ClassLoader:它負(fù)責(zé)加載 Java API 中核心類庫茸歧,是由 JVM 自帶的倦炒,無法被用戶代碼直接引用。
  • Extension ClassLoader:它負(fù)責(zé)加載 Java 的擴(kuò)展類庫软瞎,默認(rèn)情況下從 ${java.home}/lib/ext 目錄下加載類庫逢唤。
  • Application ClassLoader(也稱為 System ClassLoader):它負(fù)責(zé)加載應(yīng)用程序的類庫,即我們自己編寫的代碼涤浇。

除了這三個默認(rèn)的 ClassLoader 對象之外鳖藕,開發(fā)人員還可以根據(jù)需要創(chuàng)建自定義的 ClassLoader。它們通常用于實(shí)現(xiàn)特定的功能只锭,如動態(tài)更新應(yīng)用程序著恩、熱加載類等。

8蜻展、子線程可以啟動Activity喉誊、Service嗎?

在 Android 中纵顾,子線程不能直接啟動 Activity 或 Service伍茄。這是因?yàn)檫@些組件必須在主線程中創(chuàng)建和運(yùn)行。

如果您的應(yīng)用程序需要從子線程中啟動 Activity 或 Service施逾,則可以使用以下方法:

  • 使用 Handler 將操作傳遞回主線程并在主線程中啟動 Activity 或 Service幻林。
  • 使用 runOnUiThread() 方法將操作傳遞回主線程并在主線程中啟動 Activity 或 Service贞盯。
  • 使用 AsyncTask 或 RxJava 等異步編程框架音念,在 doInBackground() 方法中執(zhí)行計(jì)算密集型操作沪饺,并在 onPostExecute() 方法中啟動 Activity 或 Service。

無論您選擇哪種方法闷愤,都應(yīng)該避免在主線程中執(zhí)行耗時操作整葡,以避免出現(xiàn)應(yīng)用程序無響應(yīng)(ANR)的情況。

9讥脐、下拉通知欄遭居,會影響Activity生命周期嗎?

下拉通知欄不會直接影響 Activity 的生命周期旬渠。當(dāng)用戶下拉通知欄時俱萍,Activity 仍然處于活動狀態(tài)并可以響應(yīng)事件。

但是告丢,如果您的應(yīng)用程序正在執(zhí)行某些與 Activity 生命周期相關(guān)的操作(例如保存和恢復(fù)數(shù)據(jù)枪蘑、處理配置更改等),則可能會影響 Activity 的生命周期岖免。此時岳颇,您需要確保正確地處理這些事件,并且在必要的情況下保存和恢復(fù) Activity 狀態(tài)颅湘。

值得注意的是话侧,當(dāng)用戶下拉通知欄時,系統(tǒng)可能會暫痛巢危或停止 Activity瞻鹏。如果系統(tǒng)需要釋放資源以支持其他應(yīng)用程序或操作系統(tǒng)功能,則可能會發(fā)生這種情況鹿寨。但是新博,這只會在極端情況下發(fā)生,并且您的應(yīng)用程序應(yīng)該能夠正確處理這種情況释移。


參考作者:sososeen09
鏈接:http://www.reibang.com/p/13b07beacb1f

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末叭披,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子玩讳,更是在濱河造成了極大的恐慌涩蜘,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件熏纯,死亡現(xiàn)場離奇詭異同诫,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)樟澜,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進(jìn)店門误窖,熙熙樓的掌柜王于貴愁眉苦臉地迎上來叮盘,“玉大人,你說我怎么就攤上這事霹俺∪岷穑” “怎么了?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵丙唧,是天一觀的道長愈魏。 經(jīng)常有香客問我,道長想际,這世上最難降的妖魔是什么培漏? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮胡本,結(jié)果婚禮上牌柄,老公的妹妹穿的比我還像新娘。我一直安慰自己侧甫,他們只是感情好珊佣,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著闺骚,像睡著了一般彩扔。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上僻爽,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天虫碉,我揣著相機(jī)與錄音,去河邊找鬼胸梆。 笑死敦捧,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的碰镜。 我是一名探鬼主播兢卵,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼绪颖!你這毒婦竟也來了秽荤?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤柠横,失蹤者是張志新(化名)和其女友劉穎窃款,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體牍氛,經(jīng)...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡晨继,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了搬俊。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片紊扬。...
    茶點(diǎn)故事閱讀 39,785評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡蜒茄,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出餐屎,到底是詐尸還是另有隱情檀葛,我是刑警寧澤,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布啤挎,位于F島的核電站驻谆,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏庆聘。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一勺卢、第九天 我趴在偏房一處隱蔽的房頂上張望伙判。 院中可真熱鬧,春花似錦黑忱、人聲如沸宴抚。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽菇曲。三九已至,卻和暖如春抚吠,著一層夾襖步出監(jiān)牢的瞬間常潮,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工楷力, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留喊式,地道東北人。 一個月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓萧朝,卻偏偏與公主長得像岔留,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子检柬,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評論 2 354

推薦閱讀更多精彩內(nèi)容