【Android源碼】Activity的啟動流程

通常情況下,我們在顯式調(diào)用Activity的情況下,只需要通過如下代碼就能啟動一個Activity:

Intent intent = new Intent(this, TestActivity.class);
startActivity(intent);

通過上面的代碼就能啟動一個Activity,之后新的Activity就能被系統(tǒng)展示給用戶。
那么系統(tǒng)是如何啟動一個Activity?
新的Activity對象是在什么情況下被創(chuàng)建的?
onCreate是在什么時機(jī)被系統(tǒng)回調(diào)的?

帶著這些問題,我們來一起分析下Activity的啟動過程。

我們通過startActivity開始分析:

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());
       }
       if (requestCode >= 0) {
           // If this start is requesting a result, we can avoid making
           // the activity visible until the result is received.  Setting
           // this code during onCreate(Bundle savedInstanceState) or onResume() will keep the
           // activity hidden during this time, to avoid flickering.
           // This can only be done when a result is requested because
           // that guarantees we will get information back when the
           // activity is finished, no matter what happens to it.
           mStartedActivity = true;
       }

       cancelInputsAndStartExitTransition(options);
       // TODO Consider clearing/flushing other event sources and events for child windows.
   } else {
       if (options != null) {
           mParent.startActivityFromChild(this, intent, requestCode, options);
       } else {
           // Note we want to go through this method for compatibility with
           // existing applications that may have overridden it.
           mParent.startActivityFromChild(this, intent, requestCode);
       }
   }
}

通過上面的代碼可以發(fā)現(xiàn)調(diào)用了mInstrumentation.execStartActivity(this, mMainThread.getApplicationThread(), mToken, this,intent, requestCode, options)這個方法:

public ActivityResult execStartActivity(
            Context who, IBinder contextThread, IBinder token, Activity target,
            Intent intent, int requestCode, Bundle options) {
   IApplicationThread whoThread = (IApplicationThread) contextThread;
   Uri referrer = target != null ? target.onProvideReferrer() : null;
   if (referrer != null) {
       intent.putExtra(Intent.EXTRA_REFERRER, referrer);
   }
   if (mActivityMonitors != null) {
       synchronized (mSync) {
           final int N = mActivityMonitors.size();
           for (int i=0; i<N; i++) {
               final ActivityMonitor am = mActivityMonitors.get(i);
               if (am.match(who, null, intent)) {
                   am.mHits++;
                   if (am.isBlocking()) {
                       return requestCode >= 0 ? am.getResult() : null;
                   }
                   break;
               }
           }
       }
   }
   try {
       intent.migrateExtraStreamToClipData();
       intent.prepareToLeaveProcess(who);
       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;
}

通過上面的代碼可以發(fā)現(xiàn),啟動Activity的真正實(shí)現(xiàn)是ActivityManangerNative.getDefault()startActivity方法來完成的。

public abstract class ActivityManagerNative extends Binder implements IActivityManager{
}

通過觀察ActivityManangerNative可以發(fā)現(xiàn)繼承了Binder并實(shí)現(xiàn)了IActivityManager,所以ActivityManangerNative是一個Binder對象:

    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;
   }
};

通過ActivityManangerNative.getDefault()方法可以看到這是一個單例的封裝:

IBinder b = ServiceManager.getService("activity");

通過ServiceManger來獲取到真正的Binder對象并返回,而這個對象就是ActivityManagerService,那么怎么確定就是它呢?可以參考PackageManagerService的創(chuàng)建過程

到此為止,Activity的啟動過程就轉(zhuǎn)到了ActivityManagerService中(不同版本的源碼略有區(qū)別):

   ActivityManagerService.startActivity
-> ActivityManagerService.startActivityAsUser
-> ActivityStarter.startActivityMayWait
-> ActivityStarter.startActivityLocked
-> ActivityStarter.startActivityUnchecked
-> ActivityStackSupervisor.resumeFocusedStackTopActivityLocked
-> ActivityStack.resumeTopActivityUncheckedLocked
-> ActivityStack.resumeTopActivityInnerLocked
-> ActivityStackSupervisor.startSpecificActivityLocked
-> ActivityStackSupervisor.realStartActivityLocked

通過不斷的跳轉(zhuǎn)最終跳轉(zhuǎn)到了ActivityStackSupervisor.realStartActivityLocked方法中:

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);

app.threadIApplicationThread的類型:

public interface IApplicationThread extends IInterface {}

IApplicationThreadIInterface類型,所以它也是一個Binder類型的接口,從IApplicationThread的聲明可以看出,其中包含了大量的啟動、停止Activity的接口,還包含啟動和停止Service的接口。通過聲明可以猜測這個Binder接口完成了大量的Activity和Service啟動和停止相關(guān)的功能。

那么IApplicationThread的實(shí)現(xiàn)又是什么呢?

我們通過追溯thread可以知道是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) {

  updateProcessState(procState, false);

  ActivityClientRecord r = new ActivityClientRecord();

  r.token = token;
  r.ident = ident;
  r.intent = intent;
  r.referrer = referrer;
  r.voiceInteractor = voiceInteractor;
  r.activityInfo = info;
  r.compatInfo = compatInfo;
  r.state = state;
  r.persistentState = persistentState;

  r.pendingResults = pendingResults;
  r.pendingIntents = pendingNewIntents;

  r.startsNotResumed = notResumed;
  r.isForward = isForward;

  r.profilerInfo = profilerInfo;

  r.overrideConfig = overrideConfig;
  updatePendingConfiguration(curConfig);

  sendMessage(H.LAUNCH_ACTIVITY, r);
}

這個方法很簡單,就是構(gòu)造了ActivityClientRecord并賦值,之后發(fā)送一個消息給Handler,這個Handler就是主線程的H:

case LAUNCH_ACTIVITY: {
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
        final ActivityClientRecord r = (ActivityClientRecord) msg.obj;
        
        r.packageInfo = getPackageInfoNoCheck(
                r.activityInfo.applicationInfo, r.compatInfo);
        handleLaunchActivity(r, null, "LAUNCH_ACTIVITY");
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
    } break;
    
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
    Activity a = performLaunchActivity(r, customIntent);
}

最終performLaunchActivity完成了Activity對象的創(chuàng)建和啟動過程。

這個方法主要完成了這幾個操作:

  1. 通過ActivityClientRecord獲取到需要啟動的Activity的組件信息

    ActivityInfo aInfo = r.activityInfo;
    if (r.packageInfo == null) {
      r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
              Context.CONTEXT_INCLUDE_CODE);
    }
    
    ComponentName component = r.intent.getComponent();
    if (component == null) {
      component = r.intent.resolveActivity(
          mInitialApplication.getPackageManager());
      r.intent.setComponent(component);
    }
    
    if (r.activityInfo.targetActivity != null) {
      component = new ComponentName(r.activityInfo.packageName,
              r.activityInfo.targetActivity);
    }
    
    
  2. 通過類加載器創(chuàng)建Activity

    Activity activity = null;
    try {
      java.lang.ClassLoader cl = r.packageInfo.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) {
      if (!mInstrumentation.onException(activity, e)) {
          throw new RuntimeException(
              "Unable to instantiate activity " + component
              + ": " + e.toString(), e);
      }
    }
    public Activity newActivity(ClassLoader cl, String className,
       Intent intent)
       throws InstantiationException, IllegalAccessException,
       ClassNotFoundException {
        return (Activity)cl.loadClass(className).newInstance();
    }
    
  3. 通過makeApplication嘗試創(chuàng)建Application

    Application app = r.packageInfo.makeApplication(false, mInstrumentation);
    

    從makeApplication中也可以看到如果Application已經(jīng)存在了,那么就不會在創(chuàng)建Application,保證一個應(yīng)用只有一個Application對象。Application也是通過類加載器來創(chuàng)建的。

    instrumentation.callApplicationOnCreate(app);
    

    當(dāng)Application第一次創(chuàng)建之后就會調(diào)用Application的onCreate方法,這就是為什么當(dāng)啟動一個App的時候,Application會被首先調(diào)用的原因。

  4. 創(chuàng)建ContextImpl對象并通過Activity的attach方法來完成一系列操作

    Context appContext = createBaseContextForActivity(r, activity);
     CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
     Configuration config = new Configuration(mCompatConfiguration);
     if (r.overrideConfig != null) {
         config.updateFrom(r.overrideConfig);
     }
     if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "
             + r.activityInfo.name + " with config " + config);
     Window window = null;
     if (r.mPendingRemoveWindow != null && r.mPreserveWindow) {
         window = r.mPendingRemoveWindow;
         r.mPendingRemoveWindow = null;
         r.mPendingRemoveWindowManager = null;
     }
     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);
    
    

    attach方法會關(guān)聯(lián)ContextImpl對象,還會關(guān)聯(lián)Window對象,并建立自己和Window對象的關(guān)聯(lián)。

  5. 調(diào)用Activity的onCreate方法

    mInstrumentation.callActivityOnCreate(activity, r.state);
    -> activity.performCreate(icicle);
    
    final void performCreate(Bundle icicle) {
       restoreHasCurrentPermissionRequest(icicle);
       onCreate(icicle);
       mActivityTransitionState.readState(icicle);
       performCreateCommon();
    }
    

    最終調(diào)用了我們熟悉的onCreate的生命周期中,此時Activity就完成了整個的啟動過程。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,791評論 6 545
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,795評論 3 429
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,943評論 0 384
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 64,057評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,773評論 6 414
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 56,106評論 1 330
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,082評論 3 450
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 43,282評論 0 291
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,793評論 1 338
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,507評論 3 361
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,741評論 1 375
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,220評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,929評論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,325評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,661評論 1 296
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,482評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,702評論 2 380

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

  • Android Activity的啟動過程過程分析 前言 在了解Activity的啟動的過程的時候,我們需要先了解...
    真的有照片閱讀 1,289評論 0 6
  • 本文重點(diǎn)介紹應(yīng)用程序的啟動過程,應(yīng)用程序的啟動過程實(shí)際上就是應(yīng)用程序中的默認(rèn)Activity的啟動過程,本文將詳細(xì)...
    天宇sonny閱讀 409評論 1 0
  • 從源碼的角度描述Activity的啟動過程 Activity作為Android四大組件之一,也是我們平時開發(fā)中使用...
    淡雅如蘭_往事隨風(fēng)閱讀 325評論 0 0
  • 誰啟動了你的activity ? 首先拋出一個問題,當(dāng)你點(diǎn)擊桌面應(yīng)用圖標(biāo)的時候,你的Launch-Activity...
    JeremyDai閱讀 1,461評論 2 4
  • 莫問君有幾多愁, 人上有人樓外樓。 鹍鵬展翼九萬里, 敢于拼搏和奮斗。 問君能有幾多愁, 一江春水向東流。 長江后...
    講誠信的人閱讀 1,237評論 5 29