重溫四大組件(三)—Activity的啓動過程

前言

重溫四大組件第四篇,這裏分析一下Activity的啓動過程。Activity的啓動過程分爲兩種,一種是根Activity的啓動,另一種是普通Activity的啓動過程。根Activity也就是默認啓動的Activity(在AndroidMinifest.xml配置的啓動Activity)。普通Activity指的是除根Activity的其餘Activity。其中根Activity和普通Activity的啓動過程略有區別,根Activity的啓動過程涉及到了應用程序進程的啓動過程。java

接下來從根Activity的角度啓動來講。android

如下分析的代碼基於Android 9.0數據結構

Activity啓動過程當中的數據結構

咱們在看一些技術博客的時候常常會看到一些分析AMS的文章。AMS就是ActivityManagerService,顧名思義就是Activity的管理服務,但它不只僅管理Activity,其餘三個組件的啓動也經由AMS。同時,在看Activity的啓動過程以前,咱們應該瞭解一些Binder的知識。Binder是Android系統中一種跨進程通訊技術。在Activity的啓動過程當中就涉及到了Binder通訊的過程。app

Activity的啓動過程,能夠歸納爲Launcher到AMS(通過Binder通訊),從AMS到ApplicationThread(經過Binder通訊)。ide

以上介紹了AMS在Activity的啓動中承擔的做用。接下來,咱們再介紹一些在Activity啓動過程當中的一些其餘角色。函數

ActivityStack

從ActivityStack的命名能夠看出這個是Activity棧相關的。它的做用是管理和記錄一個Activity棧的Activity。接下來咱們看下ActivityStack中有哪些屬性。post

名稱 類型 說明
mService ActivityManagerService 目前AMS的引用
mRecentTasks RecentTasks 記錄一個最近使用的Activity列表
mPausingActivity ActivityRecord 目前中止狀態的Activity信息
mResumedActivity ActivityRecord 目前resume狀態的Activity信息

ActivityRecord

ActivityRecord是用來描述一個Activity的數據結構,它記錄了Activity的全部信息。學習

名稱 類型 說明
service ActivityManagerService 目前AMS的引用
info ActivityInfo 主要記錄了Activity在Manifest文件中的配置信息
launchedFromPid int 啓動Activity進程的pid
launchedFromUid int 啓動Activity進程的uid
taskAffinity String Activity啓動後所在的task
task TaskRecord 記錄了所在task的信息
app ProcessRecord 記錄了Activity啓動所在進程的信息
state ActivityState 當前Activity的狀態
theme int Activity的主題

TaskRecord

TaskRecord是關於任務棧的描述。ui

名稱 類型 說明
taskId final int 任務棧的惟一標識
affinity String 任務棧的名稱,也就是taskAffinity配置的名稱
intent Intent 啓動這個任務棧的Intent
mActivities ArrayList 按照在任務棧中歷史順序排序的Activity
mStack ActivityStack 任務棧所在的Activity棧
mService ActivityManagerService 目前AMS的引用

ProcessRecord

ProcessRecord是關於應用進程的描述。this

名稱 類型 說明
uid int 進程的uid
processName String 進程名稱
info ApplicationInfo 記錄應用程序信息

在上面介紹了Activity啓動過程當中關於Activity啓動過程當中的一些信息記錄。好比:Activity棧信息、任務棧信息以及進程信息等。

Activity的啓動工程

Activity的啓動過程是一個很複雜的過程,接下來的分析過程並不會把全部細節都分析到位。咱們分析Activity的啓動過程主要是爲了學習Android系統對Activity組件的管理過程以及對應用進程的調度。

從Launcher到AMS

咱們知道在Android系統中鎖呈現的桌面就是一個應用程序。當用戶點擊桌面上的應用圖標是就能夠啓動相應的應用程序。應用程序由Launcher啓動,調用startActivitySafely()方法。

/**Launcher.java**/
 boolean startActivitySafely(Intent intent, Object tag) {
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        try {
            startActivity(intent);
            return true;
        } catch (ActivityNotFoundException e) {
            Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
        } catch (SecurityException e) {
            Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
        }
        return false;
    }
複製代碼

能夠看到在startActivitySafely()中繼續調用startActivity()方法啓動Activity,而且在Intent中設置了flag爲FLAG_ACTIVITY_NEW_TASK表示Activity將在一個新的任務棧中啓動。這個方法就是在Activity中的。

/**Activity.java**/
public void startActivity(Intent intent, @Nullable Bundle options) {
        if (options != null) {
            startActivityForResult(intent, -1, options);
        } else {
            // Note we want to go through this call for compatibility with
            // applications that may have overridden the method.
            startActivityForResult(intent, -1);
        }
    }
複製代碼

這裏繼續調用了startActivityForResult(),而且requestCode爲-1表示Launcher不須要知道Activity的結果。

/**Activity.java**/
public void startActivityForResult(@RequiresPermission Intent intent, int requestCode, @Nullable Bundle options) {
        if (mParent == null) {
            options = transferSpringboardActivityOptions(options);
            //繼續啓動Activity
            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());
            }
            if (requestCode >= 0) {
                mStartedActivity = true;
            }
            cancelInputsAndStartExitTransition(options);
        } else {
            if (options != null) {
                mParent.startActivityFromChild(this, intent, requestCode, options);
            } else {
                mParent.startActivityFromChild(this, intent, requestCode);
            }
        }
    }
複製代碼

在這裏先判斷mParent是否爲null,而後根據結果選擇走那一步。若是跟代碼的話,能夠看到mParent在attach()方法中或者setParent()方法中賦值,在根Activity的狀況中mParent爲null。因此繼續調用 mInstrumentation.execStartActivity()。

/**Instrumentation.java**/
public ActivityResult execStartActivity( Context who, IBinder contextThread, IBinder token, String target, Intent intent, int requestCode, Bundle options) {
        IApplicationThread whoThread = (IApplicationThread) contextThread;
        //......
        try {
            intent.migrateExtraStreamToClipData();
            intent.prepareToLeaveProcess(who);
            //經過Binder接口獲取AMS對象
            int result = ActivityManager.getService()
                .startActivity(whoThread, who.getBasePackageName(), intent,
                        intent.resolveTypeIfNeeded(who.getContentResolver()),
                        token, target, requestCode, 0, null, options);
            checkStartActivityResult(result, intent);
        } catch (RemoteException e) {
            throw new RuntimeException("Failure from system", e);
        }
        return null;
    }
複製代碼

在上面的方法中繼續啓動Activity,在這裏咱們能夠看到經過ActivityManager.getService()咱們就獲取到了AMS對象。接下來,咱們看下AMS的獲取過程。

/**ActivityManager.java**/
public static IActivityManager getService() {
        return IActivityManagerSingleton.get();
    }
private static final Singleton<IActivityManager> IActivityManagerSingleton =
            new Singleton<IActivityManager>() {
                @Override
                protected IActivityManager create() {
                    final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
                    final IActivityManager am = IActivityManager.Stub.asInterface(b);
                    return am;
                }
            };
複製代碼

在getService()方法中經過IActivityManagerSingleton獲取了AMS的對象。在建立IActivityManagerSingleton的方法中咱們能夠看到返回的是IActivityManager,IActivityManager就是使用了AIDL的方式生成的。

在AMS中處理Activity的啓動

從這裏開始,Activity的啓動就開始在AMS中進行了。從上面的代碼能夠知道這個過程是經過Binder通訊方式進行的。

/**ActivityManagerService.java**/
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());
    }
複製代碼

在ActivityManagerService中經過startActivity()方法繼續進行Activity的啓動。接下來咱們直接看最終的方法回調。

/**ActivityManagerService.java**/
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, boolean validateIncomingUser) {
        //......
        //從obtainStarter()中獲取了ActivityStarter對象
        return mActivityStartController.obtainStarter(intent, "startActivityAsUser")
                .setCaller(caller)
                .setCallingPackage(callingPackage)
                .setResolvedType(resolvedType)
                .setResultTo(resultTo)
                .setResultWho(resultWho)
                .setRequestCode(requestCode)
                .setStartFlags(startFlags)
                .setProfilerInfo(profilerInfo)
                .setActivityOptions(bOptions)
                .setMayWait(userId) //設置mayWait標誌
                .execute();

    }
複製代碼

在上面的方法中,AMS經過startActivityAsUser()方法最終把Activity的啓動過程轉移到了ActivityStarter中。咱們直接看下ActivityStarter的execute()方法。

/**ActivityStarter**/
int execute() {
        try {
            if (mRequest.mayWait) {
                return startActivityMayWait(mRequest.caller, mRequest.callingUid,
                       //....//);
            } else {
                return startActivity(mRequest.caller, mRequest.intent, //....//);
            }
        } finally {
            onExecutionComplete();
        }
    }
複製代碼

這裏根據mRequest.mayWait(表示咱們應該等待啓動請求的結果。)中的標誌來判斷走哪一個邏輯分支。在上面的代碼中調用setMayWait(userId),這裏將mayWait設置爲true。那麼接下來咱們繼續看startActivityMayWait()方法。

private int startActivityMayWait(//....//) {
        //......
        // Collect information about the target of the Intent.
        ActivityInfo aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags, profilerInfo); //構建Activity的信息

        synchronized (mService) {
            final ActivityStack stack = mSupervisor.mFocusedStack; //獲取Activity棧的信息
            stack.mConfigWillChange = globalConfig != null
                    && mService.getGlobalConfiguration().diff(globalConfig) != 0;
            //......
            final ActivityRecord[] outRecord = new ActivityRecord[1]; //獲取Activity的信息
            //繼續啓動Activity
            int res = startActivity(caller, intent, ephemeralIntent, resolvedType, aInfo, rInfo,
                    voiceSession, voiceInteractor, resultTo, resultWho, requestCode, callingPid,
                    callingUid, callingPackage, realCallingPid, realCallingUid, startFlags, options,
                    ignoreTargetSecurity, componentSpecified, outRecord, inTask, reason,
                    allowPendingRemoteAnimationRegistryLookup);

            Binder.restoreCallingIdentity(origId);
            //......
            return res;
        }
    }
複製代碼

咱們繼續跟代碼,接下會調用

private int startActivity(//....//) {
        //......
        ProcessRecord callerApp = null; //獲取進程信息
        if (caller != null) {
            //caller是ActivityThread中的Binder接口,用過應用程序進程則不爲null
            callerApp = mService.getRecordForAppLocked(caller); //獲取進程信息
            if (callerApp != null) {
                callingPid = callerApp.pid;
                callingUid = callerApp.info.uid;
            } 
        }
        //......
        //建立啓動Activity的信息類
        ActivityRecord r = new ActivityRecord(mService, callerApp, callingPid, callingUid,
                callingPackage, intent, resolvedType, aInfo, mService.getGlobalConfiguration(),
                resultRecord, resultWho, requestCode, componentSpecified, voiceSession != null,
                mSupervisor, checkedOptions, sourceRecord);
        if (outActivity != null) {
            outActivity[0] = r;
        }
        final ActivityStack stack = mSupervisor.mFocusedStack; //獲取有焦點的Activity棧
        //......
        //繼續啓動Activity
        return startActivity(r, sourceRecord, voiceSession, voiceInteractor, startFlags,
                true /* doResume */, checkedOptions, inTask, outActivity);
    }
複製代碼

在上面會看到根據IApplicationThread獲取應用進程信息,這裏若是應用進程沒有被建立的時候,IApplicationThread是null,而後接下來的步驟會建立應用程序進程,這裏再也不詳細說。接下來繼續進行Activity啓動的分析。

private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord, IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask, ActivityRecord[] outActivity) {
        //......
        int result = START_SUCCESS;
            if (mDoResume) {
            final ActivityRecord topTaskActivity =
                    mStartActivity.getTask().topRunningActivityLocked();
            if (!mTargetStack.isFocusable()
                    || (topTaskActivity != null && topTaskActivity.mTaskOverlay
                mTargetStack.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
                mService.mWindowManager.executeAppTransition();
            } else {
                if (mTargetStack.isFocusable() && !mSupervisor.isFocusedStack(mTargetStack)) {
                    mTargetStack.moveToFront("startActivityUnchecked");
                }
                //這裏繼續啓動Activity
                mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity,
                        mOptions);
            }
        }
        return START_SUCCESS;
    }
複製代碼

接下來啓動Activity的過程轉到ActivityStackSupervisor中。

/**ActivityStackSupervisor**/
boolean resumeFocusedStackTopActivityLocked( ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) {
        //這裏從Activity棧中啓動
        if (targetStack != null && isFocusedStack(targetStack)) {
            return targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);
        }
        //......
        return false;
    }
複製代碼

上面的代碼中繼續啓動Activity,此次啓動過程轉到ActivityStack中。

private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
        //......省略代碼
      
       boolean pausing = mStackSupervisor.pauseBackStacks(userLeaving, next, false);
        if (mResumedActivity != null) {
            //這裏若是mResumedActivity不爲null,就中止mResumedActivity
            if (DEBUG_STATES) Slog.d(TAG_STATES,
                    "resumeTopActivityLocked: Pausing " + mResumedActivity);
            pausing |= startPausingLocked(userLeaving, false, next, false);
        }
        //next是ActivityRecord對象,next.app是ProcessRecord對象,next.app.thread是IApplicationThread
        if (next.app != null && next.app.thread != null) {
            //若是都不爲null,說明應用進程已經被建立
           //......
            synchronized(mWindowManager.getWindowManagerLock()) {
                try {
                    mStackSupervisor.startSpecificActivityLocked(next, true, false);
                    return true;
                }
            }
        } else {
            ////應用進程沒有被建立
            mStackSupervisor.startSpecificActivityLocked(next, true, true);
        }
        return true;
    }
複製代碼

在上面的代碼中咱們能夠看到有一個判斷邏輯if (next.app != null && next.app.thread != null),這個是判斷應用程序進程是否被建立,從代碼中能夠看到,不管應用進程是否被建立,都會調用startSpecificActivityLocked()方法。這裏Activity的啓動又轉移到了ActivityStackSupervisor中。

除此以外,還有一個步驟是將mResumedActivity設置爲中止狀態,在咱們查看Activity的生命週期時,一個Activity啓動另一個Activity的時候,在調用過Activity的pause生命週期函數時纔會開始下一個Activity的生命週期。

/**ActivityStackSupervisor**/
void startSpecificActivityLocked(ActivityRecord r, boolean andResume, boolean checkConfig) {
        // Is this activity's application already running?
        //獲取應用進程信息
        ProcessRecord app = mService.getProcessRecordLocked(r.processName,
                r.info.applicationInfo.uid, true);
        if (app != null && app.thread != null) {
            try {
                if ((r.info.flags&ActivityInfo.FLAG_MULTIPROCESS) == 0
                        || !"android".equals(r.info.packageName)) {
                    app.addPackage(r.info.packageName, r.info.applicationInfo.longVersionCode,
                            mService.mProcessStats);
                }
                //繼續啓動Activity
                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);
    }
複製代碼

這裏就看到了若是應用進程不存在就會經過AMS建立應用進程,這裏再也不展開分析。若是應用進程存在就繼續啓動Activity。調用了realStartActivityLocked方法。

/**ActivityStackSupervisor**/ 
final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app, boolean andResume, boolean checkConfig) throws RemoteException {
                //......
                // Create activity launch transaction.
                //Android 9.0的啓動方式與其餘版本的不一樣,這裏換成了經過ClientTransaction的方式已啓動。
                final ClientTransaction clientTransaction = ClientTransaction.obtain(app.thread,
                        r.appToken);
                clientTransaction.addCallback(LaunchActivityItem.obtain(new Intent(r.intent),
                        System.identityHashCode(r), r.info,
                        // TODO: Have this take the merged configuration instead of separate global
                        // and override configs.
                        mergedConfiguration.getGlobalConfiguration(),
                        mergedConfiguration.getOverrideConfiguration(), r.compat,
                        r.launchedFromPackage, task.voiceInteractor, app.repProcState, r.icicle,
                        r.persistentState, results, newIntents, mService.isNextTransitionForward(),
                        profilerInfo));

                // 這裏用來處理Activity生命週期回調
                final ActivityLifecycleItem lifecycleItem;
                if (andResume) {
                    lifecycleItem = ResumeActivityItem.obtain(mService.isNextTransitionForward());
                } else {
                    lifecycleItem = PauseActivityItem.obtain();
                }
                clientTransaction.setLifecycleStateRequest(lifecycleItem);

                // Schedule transaction.
                mService.getLifecycleManager().scheduleTransaction(clientTransaction);
                ...

        return true;
    }
複製代碼

在上面能夠看到Android 9.0的啓動方式與其餘版本的不一樣,在Android 9.0裏主要經過回調的方式啓動Activity,最終會經過AMS中的ClientLifecycleManager.scheduleTransaction()方法調用ApplicationThread的scheduleTransaction(),最後的是執行的LaunchActivityItem的execute()方法。

/**TransactionExecutor**/
public void execute(ClientTransaction transaction) {
        final IBinder token = transaction.getActivityToken();
        //1.先執行CallBack
        executeCallbacks(transaction);
        //2.再執行Activity生命週期回調
        executeLifecycleState(transaction);
        mPendingActions.clear();
    }
複製代碼
/**LaunchActivityItem**/
public void execute(ClientTransactionHandler client, IBinder token, PendingTransactionActions pendingActions) {
        Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
        ActivityClientRecord r = new ActivityClientRecord(token, mIntent, mIdent, mInfo,
                mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor, mState, mPersistentState,
                mPendingResults, mPendingNewIntents, mIsForward,
                mProfilerInfo, client);
        client.handleLaunchActivity(r, pendingActions, null /* customIntent */);
        Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
    }
複製代碼

能夠看到這裏調用了ClientTransactionHandler的handleLaunchActivity()方法。從這裏Activity的啓動過程就從AMS中的調用切換到了ActivityThread中去了。

從AMS到ActivityThread

上面說到,Activity的啓動調用了ClientTransactionHandler的handleLaunchActivity()方法。咱們能夠發現ActivityThread是繼承自ClientTransactionHandler的。在ClientTransactionHandler中handleLaunchActivity是抽象方法,咱們直接在ActivityThread中看。

從這裏開始將開始執行Activity的生命週期函數。

/**ActivityThread**/
public Activity handleLaunchActivity(ActivityClientRecord r, PendingTransactionActions pendingActions, Intent customIntent) {
        //......
        //初始化WindowManagerService
        WindowManagerGlobal.initialize();
        final Activity a = performLaunchActivity(r, customIntent);
        //......
        return a;
    }
複製代碼

能夠看到在這裏繼續調用了

/**ActivityThread**/
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
       //......
        Activity activity = null;
        try {
            //獲取Activity實例
            java.lang.ClassLoader cl = appContext.getClassLoader();
            activity = mInstrumentation.newActivity(
                    cl, component.getClassName(), r.intent);
            StrictMode.incrementExpectedActivityCount(activity.getClass());
            r.intent.setExtrasClassLoader(cl);
            r.intent.prepareToEnterProcess();
            if (r.state != null) {
                r.state.setClassLoader(cl);
            }
        } catch (Exception e) {
            //......
        }

        try {
            //初始化Application
            Application app = r.packageInfo.makeApplication(false, mInstrumentation);

            if (activity != null) {
                //設置Context
                appContext.setOuterContext(activity);
                //調用Activity的attach()方法
                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, r.configCallback);

                if (r.isPersistable()) {
                    //調用onCreate()生命週期函數
                    mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
                } else {
                    mInstrumentation.mInstrumentation(activity, r.state);
                }
                //......
                int theme = r.activityInfo.getThemeResource();
                if (theme != 0) {
                    activity.setTheme(theme); //設置主題
                }
                //......
                r.activity = activity;
            }
            r.setState(ON_CREATE);
        }
        //......
        return activity;
    }
複製代碼

在上面的代碼能夠看到執行完Activity的attach()方法後,繼續執行Instrumentation的callActivityOnCreate()方法。

/**Instrumentation**/
public void callActivityOnCreate(Activity activity, Bundle icicle) {
        prePerformCreate(activity);
        activity.performCreate(icicle);
        postPerformCreate(activity);
    }
複製代碼

這裏能夠看到,又執行了Activity的performCreate()方法。

/****/
final void performCreate(Bundle icicle, PersistableBundle persistentState) {
        //....
        //調用onCreate()生命週期方法
        if (persistentState != null) {
            onCreate(icicle, persistentState);
        } else {
            onCreate(icicle);
        }
    }
複製代碼

在上面的代碼中調用了Activity的onCreate()生命週期方法。到這裏,在上面講到的TransactionExecutor的execute()方法中的回調已經執行完畢,接下來就是開始執行生命週期相關的回調。

咱們在分析上面代碼的時候知道,生命週期回調是一個ResumeActivityItem。

/**ResumeActivityItem**/ 
public void execute(ClientTransactionHandler client, IBinder token, PendingTransactionActions pendingActions) {
        Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityResume");
        client.handleResumeActivity(token, true /* finalStateRequest */, mIsForward,
                "RESUME_ACTIVITY");
        Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
    }
複製代碼

能夠看到這裏有調用了handleResumeActivity()方法。

public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward, String reason) {
      
        final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason); 
    }
複製代碼
public ActivityClientRecord performResumeActivity(IBinder token, boolean finalStateRequest, String reason) {
            //執行Activity的performResume
            r.activity.performResume(r.startsNotResumed, reason);

            r.state = null;
            r.persistentState = null;
            r.setState(ON_RESUME);
        } catch (Exception e) {
          
        }
        return r;
    }
複製代碼

在上面的代碼中調用了Activity的performResume()方法。進而調用Activity的onResume()方法。這時Activity就呈現到了界面。Activity也算啓動完成。

總結

上面以根Activity的視角分析了Activity的啓動過程。整個分析下來,感受到Activity的啓動仍是十分複雜的,可是在也並不須要面面俱到,可以把握大致,流程理解Android在啓動Activity的過程當中是怎麼調度的,這樣就達到了咱們的目的。

相關文章
相關標籤/搜索