轉(zhuǎn)自: https://blog.csdn.net/u011631275/article/details/47337385
很多做Android應(yīng)用層開發(fā)的同學(xué)都知道UI主線程這個說法,且很多初學(xué)者在它身上吃了不少虧,常見的錯誤如“在主線程中做耗時的操作,比如下載大文件”。盡管我們已經(jīng)非常熟悉這個所謂的“主線程”了,但是恐怕并沒有多少人對它有一個清晰的認(rèn)識。
作為一個Android應(yīng)用層的開發(fā)人員,如果你想開發(fā)出性能更優(yōu),體驗更好的app,那么了解它是必須的。所有的ui效果,事件處理都是在主線程執(zhí)行的,我們怎么能不了解它呢?接下來開始我們的代碼之旅吧。
在閱讀下文之前,我希望大家能準(zhǔn)備一份android系統(tǒng)源代碼,我的是4.0的,然后是一個閱讀源碼的工具,我用的是source insight。
(一)、簡單來說說主線程是如何啟動的
我們的故事從哪里開始說起呢?首先考慮這么個問題:主線程是什么時候會啟動?我們都知道當(dāng)我們點擊手機應(yīng)用列表的圖標(biāo)后,應(yīng)用就會啟動,所以這里必然會有主線程的啟動。手機的桌面、應(yīng)用列表等其實也是一個app,這個應(yīng)用叫做Launcher。
在系統(tǒng)源碼目錄下,有一個packages目錄,這個目錄下都是android系統(tǒng)app的源代碼,Launcher的源碼就在里面。
我們找到路徑android4.0\packages\apps\Launcher2\src\com\android\launcher2\Launcher.java文件,如果你的系統(tǒng)源碼和我版本不一致,那可能會有不一樣的路徑。一般來說packages下或其子目錄下一定有個應(yīng)用叫Launcher2的應(yīng)用,有個Launcher.java的類,如果你是用source insight閱讀源碼的,那很方便就能根據(jù)類名搜索到。
Launcher.java即應(yīng)用列表的Activity,其中有一個onClick函數(shù)(我省略掉非重要代碼),為點擊圖標(biāo)的點擊事件,我們來看看點擊圖標(biāo)時,程序做了啥?
public void onClick(View v) {
.....
Object tag = v.getTag();
if (tag instanceof ShortcutInfo) {
final Intent intent = ((ShortcutInfo) tag).intent;
int[] pos = new int[2];
v.getLocationOnScreen(pos);
intent.setSourceBounds(new Rect(pos[0], pos[1],
pos[0] + v.getWidth(), pos[1] + v.getHeight()));
boolean success = startActivitySafely(intent, tag);
....
} else if (tag instanceof FolderInfo) {
....
} else if (v == mAllAppsButton) {
.....
}
}
boolean startActivitySafely(Intent intent, Object tag) {
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); //注意這里的標(biāo)志 是新的task
try {
startActivity(intent);
return true;
} catch (ActivityNotFoundException e) {
....
} catch (SecurityException e) {
......
}
return false;
}
原來Launcher內(nèi)部啟動應(yīng)用也是通過startActivity。
我們先明確這么幾個概念,這幾個概念不了解的同學(xué)不需要去深究,而我也不可能去細(xì)說,因為光這兩個機制足夠?qū)懸槐緯N覀冞@里的重點是ui主線程。
android系統(tǒng)框架層有一個服務(wù)叫ActivityManagerService,它運行在系統(tǒng)的某個進(jìn)程中。
android系統(tǒng)通過binder機制實現(xiàn)進(jìn)程間通信,應(yīng)用開發(fā)中常見的aidl就是對binder的一種封裝。我們只要知道進(jìn)程之間能通過這種機制遠(yuǎn)程調(diào)用其它進(jìn)程的函數(shù)并傳遞數(shù)據(jù)。
我們繼續(xù),Launcher的startActivity運行在Launcher這個應(yīng)用的進(jìn)程中,它會通過binder機制告訴ActivityManagerSertvice我需要創(chuàng)建一個新的Activity了。ActivityManagerService中會根據(jù)intent中的flag Intent.FLAG_ACTIVITY_NEW_TASK判斷出新的Activity是運行在新的進(jìn)程中,于是會創(chuàng)建一個新的進(jìn)程(新的進(jìn)程最終是通過linux的fork函數(shù)拷貝zygote進(jìn)程來實現(xiàn)的,學(xué)過linux系統(tǒng)開發(fā)的應(yīng)該會很熟悉,這又是另一個故事了,我們這里不詳細(xì)分析)。新的進(jìn)程會加載ActivityThread.java類,并執(zhí)行它的main函數(shù), 主角終于出現(xiàn)了,自此,主線程從main函數(shù)開始執(zhí)行了。
好了,知道了主線程是如何啟動的,接下去才是這篇的重點。
(二)、主線程中到底做了什么
public static void main(String[] args) {
....
Looper.prepareMainLooper();
if (sMainThreadHandler == null) {
sMainThreadHandler = new Handler();
}
ActivityThread thread = new ActivityThread();
thread.attach(false);
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
public static void prepareMainLooper() {
prepare();
setMainLooper(myLooper());
myLooper().mQueue.mQuitAllowed = false;
}
public static void prepare() {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper());
}
private Looper() {
mQueue = new MessageQueue();
....
}
Looper、MessageQueue有沒有很熟悉,簡單來說,android中的每個線程具備這樣一種能力:創(chuàng)建自己獨有的Looper對象,和一個獨有的MessageQueue,MessageQueue是一個消息隊列,里面存放有很多消息。Looper對象會通過loop()函數(shù)不斷循環(huán)從MessageQueue中取出消息并處理,而當(dāng)MessageQueue中沒有消息時,loop()函數(shù)將阻塞在那,直到有消息為止。那么消息是誰塞進(jìn)MessageQueue的呢,塞消息的方法有很多,但是android為我們封裝了Handler來簡化這種機制。
來看代碼理解
prepare()中sThreadLocal為線程局部變量,即只當(dāng)前線程可訪問,如果當(dāng)前線程還沒有這個局部變量,就創(chuàng)建新的looper對象,我們來看Looper的構(gòu)造函數(shù),它內(nèi)部創(chuàng)建了一個MessageQueue對象mQueue。
myLooper()獲取前面創(chuàng)建的Looper對象
public static Looper myLooper() {
return sThreadLocal.get();
}
setMainLooper將創(chuàng)建的Looper對象設(shè)置為主Looper。
ActivityThread thread = new ActivityThread();
thread.attach(false);
下面是attach函數(shù)的關(guān)鍵代碼 , ActivityManagerNative為ActivityManagerService的本地調(diào)用類,也就是說我們可以通過
ActivityManagerNative遠(yuǎn)程調(diào)用ActivityManagerService進(jìn)程中的方法,以下代碼其實就是遠(yuǎn)程調(diào)用ActivityManagerService的attachApplication(mAppThread)方法。
private void attach(boolean system) {
sThreadLocal.set(this);
mSystemThread = system;
if (!system) {
.....
IActivityManager mgr = ActivityManagerNative.getDefault();
try {
mgr.attachApplication(mAppThread); //注意里面?zhèn)鞯膮?shù)
} catch (RemoteException ex) {
// Ignore
}
} else {
......
}
......
}
見代碼android4.0\frameworks\base\services\java\com\android\server\am\ActivityManagerService.java的attachApplication(IApplicationThread thread)函數(shù)
public final void attachApplication(IApplicationThread thread) {
synchronized (this) {
...
attachApplicationLocked(thread, callingPid);
...
}
}
下面這段代碼很長,但是我們只需要關(guān)心我們需要關(guān)注的代碼,也就是會和主線程交互的部分,
private final boolean attachApplicationLocked(IApplicationThread thread,
int pid) {
....
thread.bindApplication(processName, appInfo, providers,
app.instrumentationClass, profileFile, profileFd, profileAutoStop,
app.instrumentationArguments, app.instrumentationWatcher, testMode,
isRestrictedBackupMode || !normalMode, app.persistent,
mConfiguration, app.compat, getCommonServicesLocked(),
mCoreSettingsObserver.getCoreSettingsLocked());
.....
if (mMainStack.realStartActivityLocked(hr, app, true, true)) {
didSomething = true;
}
....
}
attachApplicationLocked中調(diào)用了IApplicationThread的bindApplication函數(shù),IApplicationThread是什么?我們回到attach(boolean system)函數(shù)里,mgr.attachApplication(mAppThread);
final ApplicationThread mAppThread = new ApplicationThread();
其實IApplicationThread就是ApplicationThread的本地遠(yuǎn)程調(diào)用類,即這里在ActivityManagerService的進(jìn)程中調(diào)用bindApplication函數(shù),會通過binder機制最終調(diào)用ApplicationThread中的bindApplication函數(shù)。ApplicationThread就定義在ActivityThread.java類中,
public final void bindApplication(String processName,
ApplicationInfo appInfo, List<ProviderInfo> providers,
ComponentName instrumentationName, String profileFile,
ParcelFileDescriptor profileFd, boolean autoStopProfiler,
Bundle instrumentationArgs, IInstrumentationWatcher instrumentationWatcher,
int debugMode, boolean isRestrictedBackupMode, boolean persistent,
Configuration config, CompatibilityInfo compatInfo,
Map<String, IBinder> services, Bundle coreSettings) {
if (services != null) {
// Setup the service cache in the ServiceManager
ServiceManager.initServiceCache(services);
}
setCoreSettings(coreSettings);
AppBindData data = new AppBindData();
data.processName = processName;
data.appInfo = appInfo;
data.providers = providers;
data.instrumentationName = instrumentationName;
data.instrumentationArgs = instrumentationArgs;
data.instrumentationWatcher = instrumentationWatcher;
data.debugMode = debugMode;
data.restrictedBackupMode = isRestrictedBackupMode;
data.persistent = persistent;
data.config = config;
data.compatInfo = compatInfo;
data.initProfileFile = profileFile;
data.initProfileFd = profileFd;
data.initAutoStopProfiler = false;
//這句是最關(guān)鍵的代碼
queueOrSendMessage(H.BIND_APPLICATION, data);
}
private void queueOrSendMessage(int what, Object obj) {
queueOrSendMessage(what, obj, 0, 0);
}
private void queueOrSendMessage(int what, Object obj, int arg1, int arg2) {
synchronized (this) {
if (DEBUG_MESSAGES) Slog.v(
TAG, "SCHEDULE " + what + " " + mH.codeToString(what)
+ ": " + arg1 + " / " + obj);
Message msg = Message.obtain();
msg.what = what;
msg.obj = obj;
msg.arg1 = arg1;
msg.arg2 = arg2;
mH.sendMessage(msg);
}
}
看到這里是不是很熟悉,我們應(yīng)用開發(fā)中最常用的Handler就是這么使用的,那么mH是不是個Handler呢
final H mH = new H();
private class H extends Handler {
….
}
果然如我們上面猜測的,它確實是個Handler,我們再來看看sendMessage內(nèi)部實現(xiàn)
public final boolean sendMessage(Message msg)
{
return sendMessageDelayed(msg, 0);
}
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
public boolean sendMessageAtTime(Message msg, long uptimeMillis)
{
boolean sent = false;
MessageQueue queue = mQueue;
if (queue != null) {
//注意這句 這里將Message的target變量賦值為當(dāng)前Handler對象
msg.target = this;
//這里就是向消息隊列中添加一個Message
sent = queue.enqueueMessage(msg, uptimeMillis);
}
else {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
}
return sent;
}
即bindApplication中通過Handler的sendMessage向當(dāng)前線程的MessageQueue塞進(jìn)了一個消息,這個消息的what值為H.BIND_APPLICATION。
好了,回到我們的ActivityThread的main函數(shù)中。 thread.attach(false);的分析到此為止,我們總結(jié)一下分析到現(xiàn)在,main函數(shù)中完成了哪些工作
1.Looper.prepareMainLooper();創(chuàng)建了一個Looper對象和一個MessageQueue對象
2.thread.attach(false);向MessageQueue隊列中加入了一個Message,這個Message的what為H.BIND_APPLICATION
接著來看 Looper.loop();依然是留下最關(guān)鍵的代碼
public static void loop() {
Looper me = myLooper();
...
MessageQueue queue = me.mQueue;
...
while (true) {
Message msg = queue.next(); // might block
....
msg.target.dispatchMessage(msg);
....
msg.recycle();
}
}
獲取Looper對象,再從Looper對象中拿到MessageQueue對象,調(diào)用它的next()函數(shù)拿隊列中下一個消息,然后調(diào)用Message對象的target成員的dispatchMessage函數(shù),target其實就是一個Handler對象,回到上面的Handler的sendMessageAtTime函數(shù)中,有一句 msg.target = this;所以這里在取出消息后,調(diào)用的就是這個消息對應(yīng)的Handler的dispatchMessage函數(shù)。
我們這里處理的第一個消息就是前面thread.attach(false);調(diào)用后向messageQueue中添加的消息,所以主線程在loop()函數(shù)中會調(diào)用H的dispatchMessage函數(shù),H繼承了Handler,但是并沒有重寫dispatchMessage函數(shù),所以調(diào)用的還是Handler本身的dispatchMessage函數(shù)。
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
這里處理消息有三種方式,首先判斷消息對象中的callback是不是空,不為空的話直接執(zhí)行callback的run函數(shù)。為空的話在判斷當(dāng)前Handler有沒有回調(diào)接口mCallback是不是為空,不為空就回調(diào)mCallback的handleMessage(msg)。最后才會調(diào)用Handler自身的 handleMessage(msg);
一般應(yīng)用開發(fā)中最常用的處理方式就是最后一種。接下來我們就看H類的handleMessage(msg);
private class H extends Handler {
....
public static final int BIND_APPLICATION = 110;
public void handleMessage(Message msg) {
if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + msg.what);
switch (msg.what) {
...
case BIND_APPLICATION:
AppBindData data = (AppBindData)msg.obj;
handleBindApplication(data);
break;
...
}
if (DEBUG_MESSAGES) Slog.v(TAG, "<<< done: " + msg.what);
}
....}
之前向消息隊列發(fā)消息時 what值為H.BIND_APPLICATION,所以我們直接找到H.BIND_APPLICATION,取出msg中app相關(guān)的信息,然后調(diào)用handleBindApplication(data);
private void handleBindApplication(AppBindData data) {
......
Application app = data.info.makeApplication(data.restrictedBackupMode, null);
mInitialApplication = app;
...
try {
mInstrumentation.callApplicationOnCreate(app);
} catch (Exception e) {
....
}
}
handleBindApplication中調(diào)用makeApplication函數(shù),該函數(shù)中根據(jù)app信息中Application類的路徑加載并創(chuàng)建對象,然后調(diào)用callApplicationOnCreate函數(shù)。callApplicationOnCreate中調(diào)用Application對象的onCreate函數(shù)。原來我們在應(yīng)用開發(fā)中常用的Application的onCreate就是這里調(diào)用的呀。
public Application makeApplication(boolean forceDefaultAppClass,
Instrumentation instrumentation) {
....
Application app = null;
String appClass = mApplicationInfo.className;
java.lang.ClassLoader cl = getClassLoader();
ContextImpl appContext = new ContextImpl();
appContext.init(this, null, mActivityThread);
app = mActivityThread.mInstrumentation.newApplication(
cl, appClass, appContext);
appContext.setOuterContext(app);
...
return app;
}
public void callApplicationOnCreate(Application app) {
app.onCreate();
}
到這里我們第一個消息處理就完成了,但是loop()函數(shù)卻不會退出,注意它是一個死循環(huán),處理完一個緊接著取下一個消息。那些我們熟悉的Activity的onCreate onResume等回調(diào)函數(shù)都是在loop()中處理消息時執(zhí)行的,關(guān)于Activity的創(chuàng)建我們在后面詳細(xì)分析。
接著上面說,現(xiàn)在我們的主線程已經(jīng)處理了第一個Message,在這個處理中執(zhí)行了Application的onCreate函數(shù),緊接著就是等待第二個消息了。
那么第二個消息是什么時候發(fā)送的呢?
private final boolean attachApplicationLocked(IApplicationThread thread,
int pid) {
....
thread.bindApplication(processName, appInfo, providers,
app.instrumentationClass, profileFile, profileFd, profileAutoStop,
app.instrumentationArguments, app.instrumentationWatcher, testMode,
isRestrictedBackupMode || !normalMode, app.persistent,
mConfiguration, app.compat, getCommonServicesLocked(),
mCoreSettingsObserver.getCoreSettingsLocked());
.....
if (mMainStack.realStartActivityLocked(hr, app, true, true)) {
didSomething = true;
}
....
}
我們回到上一篇的attachApplicationLocked函數(shù),在這個函數(shù)中,不僅調(diào)用thread.的bindApplication函數(shù)(這個函數(shù)的作用上一節(jié)已經(jīng)說過了)。還調(diào)用了mMainStack.realStartActivityLocked(hr, app, true, true)
final boolean realStartActivityLocked(ActivityRecord r,
ProcessRecord app, boolean andResume, boolean checkConfig)
throws RemoteException {
....
app.thread.scheduleLaunchActivity(new Intent(r.intent), r,
System.identityHashCode(r), r.info, mService.mConfiguration,
r.compat, r.icicle, results, newIntents, !andResume,
mService.isNextTransitionForward(), profileFile, profileFd,
profileAutoStop);
...
}
realStartActivityLocked中再次遠(yuǎn)程調(diào)用ApplicationThread的scheduleLaunchActivity函數(shù)
public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
ActivityInfo info, Configuration curConfig, CompatibilityInfo compatInfo,
Bundle state, List<ResultInfo> pendingResults,
List<Intent> pendingNewIntents, boolean notResumed, boolean isForward,
String profileName, ParcelFileDescriptor profileFd, boolean autoStopProfiler) {
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);
//和上一篇一樣 通過這個函數(shù)向MessageQueue中添加一個消息,what值為LAUNCH_ACTIVITY
queueOrSendMessage(H.LAUNCH_ACTIVITY, r);
}
看到了嗎,就是通過 queueOrSendMessage添加消息的,這個函數(shù)上一節(jié)已經(jīng)有過說明。
loop()中取出該消息,分發(fā)到mH中處理該消息
public void handleMessage(Message msg) {
if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + msg.what);
switch (msg.what) {
case LAUNCH_ACTIVITY: {
ActivityClientRecord r = (ActivityClientRecord)msg.obj;
r.packageInfo = getPackageInfoNoCheck(
r.activityInfo.applicationInfo, r.compatInfo);
handleLaunchActivity(r, null);
} break;
......
}
}
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
....
Activity a = performLaunchActivity(r, customIntent);
....
}
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
.....
Activity activity = null;
try {
//獲取類加載器,創(chuàng)建activity對象
java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
....
} catch (Exception e) {
....
}
try {
//獲取當(dāng)前Application對象,因為前面已經(jīng)創(chuàng)建過了,所以這里直接返回
Application app = r.packageInfo.makeApplication(false, mInstrumentation);
...
if (activity != null) {
ContextImpl appContext = new ContextImpl();
appContext.init(r.packageInfo, r.token, this);
appContext.setOuterContext(activity);
CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
Configuration config = new Configuration(mCompatConfiguration);
...
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstances, config);
...
activity.mCalled = false;
mInstrumentation.callActivityOnCreate(activity, r.state);
...
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);
...
}
}
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;
}
performLaunchActivity函數(shù)中主要做了這么幾件事
1.創(chuàng)建Activity對象。2.初始化activity對象的上下文
3.為當(dāng)前activity創(chuàng)建窗口。 4.分別調(diào)用activity的onCreate onResume等函數(shù),完成應(yīng)用程序希望在特定時刻完成的操作。
final void attach(Context context, ActivityThread aThread,
Instrumentation instr, IBinder token, int ident,
Application application, Intent intent, ActivityInfo info,
CharSequence title, Activity parent, String id,
NonConfigurationInstances lastNonConfigurationInstances,
Configuration config) {
attachBaseContext(context);
mFragments.attachActivity(this);
mWindow = PolicyManager.makeNewWindow(this);
mWindow.setCallback(this);
mWindow.getLayoutInflater().setPrivateFactory(this);
if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
mWindow.setSoftInputMode(info.softInputMode);
}
if (info.uiOptions != 0) {
mWindow.setUiOptions(info.uiOptions);
}
mUiThread = Thread.currentThread();
....
}
PolicyManager.makeNewWindow(this);
創(chuàng)建顯示的窗口對象, mWindow.setCallback(this);
為窗口對象設(shè)置回調(diào)接口,Activity實現(xiàn)了該接口。
回到performLaunchActivity函數(shù)中,mInstrumentation.callActivityOnCreate(activity, r.state);
public void callActivityOnCreate(Activity activity, Bundle icicle) {
....
activity.performCreate(icicle);
....
}
final void performCreate(Bundle icicle) {
onCreate(icicle);
mVisibleFromClient = !mWindow.getWindowStyle().getBoolean(
com.android.internal.R.styleable.Window_windowNoDisplay, false);
mFragments.dispatchActivityCreated();
}
callActivityOnCreate中通過Activity的performCreate函數(shù)調(diào)用了Activity的onCreate和fragment的onCreate。
if (!r.activity.mFinished) {
activity.performStart();
r.stopped = false;
}
首次打開activity, r.activity.mFinished==false,所有執(zhí)行activity.performStart();內(nèi)部調(diào)用了activity的onStart()和fragment的onStart函數(shù)。
mInstrumentation.callActivityOnPostCreate(activity, r.state);
調(diào)用Activity的onPostCreate()函數(shù)
回到 handleLaunchActivity函數(shù)中, handleResumeActivity(r.token, false, r.isForward);它內(nèi)部調(diào)用Activity的onResume函數(shù),并繪制了界面。