轉載請註明出處:http://blog.csdn.net/singwhatiwanna/article/details/18154335
Activity是Android中一個很重要的概念,堪稱四大組件之首,關於Activity有很多內容,比如生命週期和啟動Flags,這二者想要說清楚,恐怕又要寫兩篇長文,更何況分析它們的源碼呢。不過本文的側重點不是它們,我要介紹的是一個Activity典型的啟動過程,本文會從源碼的角度對其進行分析。我們知道,當startActivity被調用的時候,可以啟動一個Activity,但是你知道這個Activity是如何被啟動的嗎?每個Activity也是一個對象,你知道這個對象是啥時候被建立的嗎(也就是說它的構造方法是什麼時候被調用的)?為什麼onCreate是Activity的執行入口?所有的這一切都被系統封裝好了,對我們來說是透明的,我們使用的時候僅僅是傳遞一個intent然後startActivity就可以達到目的了,不過,閱讀了本文以後,你將會瞭解它的背後到底做了哪些事情。在分析之前,我先介紹幾個類:
首先看入口
code:Activity#startActivity
@Overridepublic void startActivity(Intent intent) {startActivity(intent, null);}@Overridepublic void startActivity(Intent intent, 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);}}public void startActivityForResult(Intent intent, int requestCode) {startActivityForResult(intent, requestCode, null);}
說明:顯然,從上往下,最終都是由startActivityForResult來實現的
接著看
code:Activity#startActivityForResult
public void startActivityForResult(Intent intent, int requestCode, Bundle options) {//一般的Activity其mParent為null,mParent常用在ActivityGroup中,ActivityGroup已廢棄if (mParent == null) {//這裡會啟動新的Activity,核心功能都在mMainThread.getApplicationThread()中完成Instrumentation.ActivityResult ar =mInstrumentation.execStartActivity(this, mMainThread.getApplicationThread(), mToken, this,intent, requestCode, options);if (ar != null) { //發送結果,即onActivityResult會被調用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;}final View decor = mWindow != null ? mWindow.peekDecorView() : null;if (decor != null) {decor.cancelPendingInputEvents();}// TODO Consider clearing/flushing other event sources and events for child windows.} else {//在ActivityGroup內部的Activity調用startActivity的時候會走到這裡,內部處理邏輯和上面是類似的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);}}}
說明:上述代碼關鍵點都有注釋了,可以發現,真正開啟activity的實現在Instrumentation的execStartActivity方法中,去看看
code:Instrumentation#execStartActivity
public ActivityResult execStartActivity(Context who, IBinder contextThread, IBinder token, Activity target,Intent intent, int requestCode, Bundle options) {//核心功能在這個whoThread中完成,其內部scheduleLaunchActivity方法用於完成activity的開啟IApplicationThread whoThread = (IApplicationThread) contextThread;if (mActivityMonitors != null) {synchronized (mSync) {//先尋找一遍看是否存在這個activityfinal 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++;//如果目標activity無法開啟,直接returnif (am.isBlocking()) {return requestCode >= 0 ? am.getResult() : null;}break;}}}}try {intent.migrateExtraStreamToClipData();intent.prepareToLeaveProcess();//這裡才是真正開啟activity的地方,核心功能在whoThread中完成。int result = ActivityManagerNative.getDefault().startActivity(whoThread, who.getBasePackageName(), intent,intent.resolveTypeIfNeeded(who.getContentResolver()),token, target != null ? target.mEmbeddedID : null,requestCode, 0, null, null, options);//這個方法是專門拋異常的,它會對結果進行檢查,如果無法開啟activity,//則拋出諸如ActivityNotFoundException類似的各種異常checkStartActivityResult(result, intent);} catch (RemoteException e) {}return null;}
說明:我想再說一下這個方法checkStartActivityResult,它也專業拋異常的,看代碼,相信大家對下面的異常資訊不陌生吧,就是它乾的,其中最熟悉的非Unable to find explicit activity class莫屬了,如果你在xml中沒有註冊目標activity,此異常將會拋出。
/*package*/ static void checkStartActivityResult(int res, Object intent) { if (res >= ActivityManager.START_SUCCESS) { return; } switch (res) { case ActivityManager.START_INTENT_NOT_RESOLVED: case ActivityManager.START_CLASS_NOT_FOUND: if (intent instanceof Intent && ((Intent)intent).getComponent() != null) throw new ActivityNotFoundException( "Unable to find explicit activity class " + ((Intent)intent).getComponent().toShortString() + "; have you declared this activity in your AndroidManifest.xml?"); throw new ActivityNotFoundException( "No Activity found to handle " + intent); case ActivityManager.START_PERMISSION_DENIED: throw new SecurityException("Not allowed to start activity " + intent); case ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT: throw new AndroidRuntimeException( "FORWARD_RESULT_FLAG used while also requesting a result"); case ActivityManager.START_NOT_ACTIVITY: throw new IllegalArgumentException( "PendingIntent is not an activity"); default: throw new AndroidRuntimeException("Unknown error code " + res + " when starting " + intent); } }
接下來我們要去看看IApplicationThread,因為核心功能由其內部的scheduleLaunchActivity方法來完成,由於IApplicationThread是個介面,所以,我們需要找到它的實作類別,我已經幫大家找到了,它就是ActivityThread中的內部類ApplicationThread,看下它的繼承關係:
private class ApplicationThread extends ApplicationThreadNative;
public abstract class ApplicationThreadNative extends Binder implements IApplicationThread;
可以發現,ApplicationThread還是間接實現了IApplicationThread介面,先看下這個類的結構
看完ApplicationThread的大致結構,我們應該能夠猜測到,Activity的生命週期中的resume、newIntent、pause、stop等事件都是由它觸發的,事實上,的確是這樣的。這裡,我們為了說明問題,僅僅看scheduleLaunchActivity方法
code:ApplicationThread#scheduleLaunchActivity
public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,ActivityInfo info, Configuration curConfig, CompatibilityInfo compatInfo,int procState, Bundle state, List<ResultInfo> pendingResults,List<Intent> pendingNewIntents, boolean notResumed, boolean isForward,String profileName, ParcelFileDescriptor profileFd, boolean autoStopProfiler) {updateProcessState(procState, false);ActivityClientRecord r = new ActivityClientRecord();r.token = token;r.ident = ident;r.intent = intent;r.activityInfo = info;r.compatInfo = compatInfo;r.state = state;r.pendingResults = pendingResults;r.pendingIntents = pendingNewIntents;r.startsNotResumed = notResumed;r.isForward = isForward;r.profileFile = profileName;r.profileFd = profileFd;r.autoStopProfiler = autoStopProfiler;updatePendingConfiguration(curConfig);queueOrSendMessage(H.LAUNCH_ACTIVITY, r);}
說明:上述代碼很好理解,構造一個activity記錄,然後發送一個訊息,所以,我們要看看Handler是如何處理這個訊息的,現在轉到這個Handler,它有個很短的名字叫做H
code:ActivityThread#H
//這個類太長,我只帖出了我們用到的部分private class H extends Handler {public void handleMessage(Message msg) {if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));switch (msg.what) {//這裡處理LAUNCH_ACTIVITY訊息類型case LAUNCH_ACTIVITY: {Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");ActivityClientRecord r = (ActivityClientRecord)msg.obj;r.packageInfo = getPackageInfoNoCheck(r.activityInfo.applicationInfo, r.compatInfo);//這裡處理startActivity訊息handleLaunchActivity(r, null);Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);} break;case RELAUNCH_ACTIVITY: {Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityRestart");ActivityClientRecord r = (ActivityClientRecord)msg.obj;handleRelaunchActivity(r);Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);} break;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;...}}
說明:看來還要看handleLaunchActivity
code:ActivityThread#handleLaunchActivity
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {// If we are getting ready to gc after going to the background, well// we are back active so skip it.unscheduleGcIdler();if (r.profileFd != null) {mProfiler.setProfiler(r.profileFile, r.profileFd);mProfiler.startProfiling();mProfiler.autoStopProfiler = r.autoStopProfiler;}// Make sure we are running with the most recent config.handleConfigurationChanged(null, null);if (localLOGV) Slog.v(TAG, "Handling launch of " + r);//終於到底了,大家都有點不耐煩了吧,從方法名可以看出,//performLaunchActivity真正完成了activity的調起,//同時activity會被執行個體化,並且onCreate會被調用Activity a = performLaunchActivity(r, customIntent);if (a != null) {r.createdConfig = new Configuration(mConfiguration);Bundle oldState = r.state;//看到沒,目標activity的onResume會被調用handleResumeActivity(r.token, false, r.isForward,!r.activity.mFinished && !r.startsNotResumed);if (!r.activity.mFinished && r.startsNotResumed) {// The activity manager actually wants this one to start out// paused, because it needs to be visible but isn't in the// foreground. We accomplish this by going through the// normal startup (because activities expect to go through// onResume() the first time they run, before their window// is displayed), and then pausing it. However, in this case// we do -not- need to do the full pause cycle (of freezing// and such) because the activity manager assumes it can just// retain the current state it has.try {r.activity.mCalled = false;//同時,由於新activity被調起了,原activity的onPause會被調用mInstrumentation.callActivityOnPause(r.activity);// We need to keep around the original state, in case// we need to be created again. But we only do this// for pre-Honeycomb apps, which always save their state// when pausing, so we can not have them save their state// when restarting from a paused state. For HC and later,// we want to (and can) let the state be saved as the normal// part of stopping the activity.if (r.isPreHoneycomb()) {r.state = oldState;}if (!r.activity.mCalled) {throw new SuperNotCalledException("Activity " + r.intent.getComponent().toShortString() +" did not call through to super.onPause()");}} catch (SuperNotCalledException e) {throw e;} catch (Exception e) {if (!mInstrumentation.onException(r.activity, e)) {throw new RuntimeException("Unable to pause activity "+ r.intent.getComponent().toShortString()+ ": " + e.toString(), e);}}r.paused = true;}} else {// If there was an error, for any reason, tell the activity// manager to stop us.try {ActivityManagerNative.getDefault().finishActivity(r.token, Activity.RESULT_CANCELED, null);} catch (RemoteException ex) {// Ignore}}}
說明:關於原activity和新activity之間的狀態同步,如果大家感興趣可以自己研究下,因為邏輯太複雜,我沒法把所有問題都說清楚,否則就太深入細節而淹沒了整體邏輯,研究源碼要的就是清楚整體邏輯。下面看最後一個方法,這個方法是activity的啟動過程的真正實現。
code:ActivityThread#performLaunchActivity
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {// System.out.println("##### [" + System.currentTimeMillis() + "] ActivityThread.performLaunchActivity(" + r + ")");ActivityInfo aInfo = r.activityInfo;if (r.packageInfo == null) {r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,Context.CONTEXT_INCLUDE_CODE);}//首先從intent中解析出目標activity的啟動參數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);}Activity activity = null;try {java.lang.ClassLoader cl = r.packageInfo.getClassLoader();//用ClassLoader(類載入器)將目標activity的類通過類名載入進來並調用newInstance來執行個體化一個對象//其實就是通過Activity的無參構造方法來new一個對象,對象就是在這裡new出來的。activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);StrictMode.incrementExpectedActivityCount(activity.getClass());r.intent.setExtrasClassLoader(cl);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);}}try {Application app = r.packageInfo.makeApplication(false, mInstrumentation);if (localLOGV) Slog.v(TAG, "Performing launch of " + r);if (localLOGV) Slog.v(TAG, r + ": app=" + app+ ", appName=" + app.getPackageName()+ ", pkg=" + r.packageInfo.getPackageName()+ ", comp=" + r.intent.getComponent().toShortString()+ ", dir=" + r.packageInfo.getAppDir());if (activity != null) {Context appContext = createBaseContextForActivity(r, activity);CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());Configuration config = new Configuration(mCompatConfiguration);if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "+ r.activityInfo.name + " with config " + config);activity.attach(appContext, this, getInstrumentation(), r.token,r.ident, app, r.intent, r.activityInfo, title, r.parent,r.embeddedID, r.lastNonConfigurationInstances, config);if (customIntent != null) {activity.mIntent = customIntent;}r.lastNonConfigurationInstances = null;activity.mStartedActivity = false;int theme = r.activityInfo.getThemeResource()if (theme != 0) {activity.setTheme(theme);}activity.mCalled = false;//目標activity的onCreate被調用了,到此為止,Activity被啟動了,接下來的流程就是Activity的生命週期了,//本文之前已經提到,其生命週期的各種狀態的切換由ApplicationThread內部來完成mInstrumentation.callActivityOnCreate(activity, r.state);if (!activity.mCalled) {throw new SuperNotCalledException("Activity " + r.intent.getComponent().toShortString() +" did not call through to super.onCreate()");}r.activity = activity;r.stopped = true;if (!r.activity.mFinished) {activity.performStart();r.stopped = false;}if (!r.activity.mFinished) {if (r.state != null) {mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state);}}if (!r.activity.mFinished) {activity.mCalled = false;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) {if (!mInstrumentation.onException(activity, e)) {throw new RuntimeException("Unable to start activity " + component+ ": " + e.toString(), e);}}return activity;}
相信當你看到這裡的時候,你對Activity的啟動過程應該有了一個感性的認識。Activity很複雜,特性很多,本文沒法對各個細節進行深入分析,而且就算真的對各個細節都進行了深入分析,那文章要有多長啊,還有人有耐心看下去嗎?希望本文能夠給大家帶來一些協助,謝謝大家閱讀。