Android Activity的啟動過程源碼解析
前言
Activity是Android中一個很重要的概念,堪稱四大組件之首,關于Activity有很多內(nèi)容,比如生命周期和啟動Flags,這二者想要說清楚,恐怕又要寫兩篇長文,更何況分析它們的源碼呢。不過本文的側(cè)重點不是它們,我要介紹的是一個Activity典型的啟動過程,本文會從源碼的角度對其進行分析。我們知道,當startActivity被調(diào)用的時候,可以啟動一個Activity,但是你知道這個Activity是如何被啟動的嗎?每個Activity也是一個對象,你知道這個對象是啥時候被創(chuàng)建的嗎(也就是說它的構造方法是什么時候被調(diào)用的)?為什么onCreate是Activity的執(zhí)行入口?所有的這一切都被系統(tǒng)封裝好了,對我們來說是透明的,我們使用的時候僅僅是傳遞一個intent然后startActivity就可以達到目的了,不過,閱讀了本文以后,你將會了解它的背后到底做了哪些事情。在分析之前,我先介紹幾個類:
- Activity:這個大家都熟悉,startActivity方法的真正實現(xiàn)在Activity中
- Instrumentation:用來輔助Activity完成啟動Activity的過程
- ActivityThread(包含ApplicationThread + ApplicationThreadNative + IApplicationThread):真正啟動Activity的實現(xiàn)都在這里
源碼分析
首先看入口
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來實現(xiàn)的
接著看
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) {
//發(fā)送結(jié)果,即onActivityResult會被調(diào)用
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內(nèi)部的Activity調(diào)用startActivity的時候會走到這里,內(nèi)部處理邏輯和上面是類似的
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),真正打開activity的實現(xiàn)在Instrumentation的execStartActivity方法中,去看看
code:Instrumentation#execStartActivity
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode, Bundle options) {
//核心功能在這個whoThread中完成,其內(nèi)部scheduleLaunchActivity方法用于完成activity的打開
IApplicationThread whoThread = (IApplicationThread) contextThread;
if (mActivityMonitors != null) {
synchronized (mSync) {
//先查找一遍看是否存在這個activity
final int N = mActivityMonitors.size();
for (int i=0; i<N; i++) {
final ActivityMonitor am = mActivityMonitors.get(i);
if (am.match(who, null, intent)) {
//如果找到了就跳出循環(huán)
am.mHits++;
//如果目標activity無法打開,直接return
if (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);
//這個方法是專門拋異常的,它會對結(jié)果進行檢查,如果無法打開activity,
//則拋出諸如ActivityNotFoundException類似的各種異常
checkStartActivityResult(result, intent);
} catch (RemoteException e) {
}
return null;
}
說明:我想再說一下這個方法checkStartActivityResult,它也專業(yè)拋異常的,看代碼,相信大家對下面的異常信息不陌生吧,就是它干的,其中最熟悉的非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,因為核心功能由其內(nèi)部的scheduleLaunchActivity方法來完成,由于IApplicationThread是個接口,所以,我們需要找到它的實現(xiàn)類,我已經(jīng)幫大家找到了,它就是ActivityThread中的內(nèi)部類ApplicationThread,看下它的繼承關系:
private class ApplicationThread extends ApplicationThreadNative;
public abstract class ApplicationThreadNative extends Binder implements IApplicationThread;
可以發(fā)現(xiàn),ApplicationThread還是間接實現(xiàn)了IApplicationThread接口,先看下這個類的結(jié)構

看完ApplicationThread的大致結(jié)構,我們應該能夠猜測到,Activity的生命周期中的resume、newIntent、pause、stop等事件都是由它觸發(fā)的,事實上,的確是這樣的。這里,我們?yōu)榱苏f明問題,僅僅看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記錄,然后發(fā)送一個消息,所以,我們要看看Handler是如何處理這個消息的,現(xiàn)在轉(zhuǎn)到這個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的調(diào)起,
//同時activity會被實例化,并且onCreate會被調(diào)用
Activity a = performLaunchActivity(r, customIntent);
if (a != null) {
r.createdConfig = new Configuration(mConfiguration);
Bundle oldState = r.state;
//看到?jīng)],目標activity的onResume會被調(diào)用
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被調(diào)起了,原activity的onPause會被調(diào)用
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之間的狀態(tài)同步,如果大家感興趣可以自己研究下,因為邏輯太復雜,我沒法把所有問題都說清楚,否則就太深入細節(jié)而淹沒了整體邏輯,研究源碼要的就是清楚整體邏輯。下面看最后一個方法,這個方法是activity的啟動過程的真正實現(xiàn)。
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的啟動參數(shù)
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的類通過類名加載進來并調(diào)用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被調(diào)用了,到此為止,Activity被啟動了,接下來的流程就是Activity的生命周期了,
//本文之前已經(jīng)提到,其生命周期的各種狀態(tài)的切換由ApplicationThread內(nèi)部來完成
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;
}
總結(jié)
相信當你看到這里的時候,你對Activity的啟動過程應該有了一個感性的認識。Activity很復雜,特性很多,本文沒法對各個細節(jié)進行深入分析,而且就算真的對各個細節(jié)都進行了深入分析,那文章要有多長啊,還有人有耐心看下去嗎?希望本文能夠給大家?guī)硪恍椭?,謝謝大家閱讀。 也希望大家多多支持腳本之家。
相關文章
android 添加按(power鍵)電源鍵結(jié)束通話(掛斷電話)
首先我們發(fā)現(xiàn)現(xiàn)在我們所用的android智能手機大部分都有當你在打電話時按power鍵來掛斷電話,一般都是在設置中2013-01-01
Android10.0實現(xiàn)本地音樂播放(附源碼下載)
這篇文章主要介紹了Android10.0實現(xiàn)本地音樂播放(附源碼下載),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-06-06
Android利用CircleImageView實現(xiàn)圓形頭像的方法
這篇文章主要介紹了Android利用CircleImageView實現(xiàn)圓形頭像的方法,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2016-10-10
Android自定義控件實現(xiàn)icon+文字的多種效果
這篇文章主要為大家詳細介紹了Android自定義控件實現(xiàn)icon+文字的多種效果,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-01-01

