Android源碼分析-Activity的啟動過程

 

Activity是Android中一個很重要的概念,堪稱四大組件之首,關於Activity有很多內容,比如生命周期和啟動Flags,這二者想要說清楚,恐怕又要寫兩篇長文,更何況分析它們的源碼呢。不過本文的側重點不是它們,我要介紹的是一個Activity典型的啟動過程,本文會從源碼的角度對其進行分析。我們知道,當startActivity被調用的時候,可以啟動一個Activity,但是你知道這個Activity是如何被啟動的嗎?每個Activity也是一個對象,你知道這個對象是啥時候被創建的嗎(也就是說它的構造方法是什麼時候被調用的)?為什麼onCreate是Activity的執行入口?所有的這一切都被系統封裝好瞭,對我們來說是透明的,我們使用的時候僅僅是傳遞一個intent然後startActivity就可以達到目的瞭,不過,閱讀瞭本文以後,你將會瞭解它的背後到底做瞭哪些事情。在分析之前,我先介紹幾個類:

Activity:這個大傢都熟悉,startActivity方法的真正實現在Activity中Instrumentation:用來輔助Activity完成啟動Activity的過程ActivityThread(包含ApplicationThread + ApplicationThreadNative + IApplicationThread):真正啟動Activity的實現都在這裡

源碼分析

首先看入口

code:Activity#startActivity

@Override
public void startActivity(Intent intent) {
	startActivity(intent, null);
}

@Override
public 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) {
			//先查找一遍看是否存在這個activity
			final int N = mActivityMonitors.size();
			for (int i=0; i= 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接口,先看下這個類的結構

data-cke-saved-src=https://www.aiwalls.com/uploadfile/Collfiles/20140113/20140113100359116.png

看完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 pendingResults,
		List 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很復雜,特性很多,本文沒法對各個細節進行深入分析,而且就算真的對各個細節都進行瞭深入分析,那文章要有多長啊,還有人有耐心看下去嗎?希望本文能夠給大傢帶來一些幫助,謝謝大傢閱讀。

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *