国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統(tǒng) > Android > 正文

Android線程管理之ActivityThread

2020-04-11 10:56:26
字體:
供稿:網(wǎng)友

ActivityThread功能

它管理應(yīng)用進(jìn)程的主線程的執(zhí)行(相當(dāng)于普通Java程序的main入口函數(shù)),并根據(jù)AMS的要求(通過IApplicationThread接口,AMS為Client、ActivityThread.ApplicationThread為Server)負(fù)責(zé)調(diào)度和執(zhí)行activities、broadcasts和其它操作。

在Android系統(tǒng)中,在默認(rèn)情況下,一個應(yīng)用程序內(nèi)的各個組件(如Activity、BroadcastReceiver、Service)都會在同一個進(jìn)程(Process)里執(zhí)行,且由此進(jìn)程的【主線程】負(fù)責(zé)執(zhí)行。

在Android系統(tǒng)中,如果有特別指定(通過android:process),也可以讓特定組件在不同的進(jìn)程中運(yùn)行。無論組件在哪一個進(jìn)程中運(yùn)行,默認(rèn)情況下,他們都由此進(jìn)程的【主線程】負(fù)責(zé)執(zhí)行。

【主線程】既要處理Activity組件的UI事件,又要處理Service后臺服務(wù)工作,通常會忙不過來。為了解決此問題,主線程可以創(chuàng)建多個子線程來處理后臺服務(wù)工作,而本身專心處理UI畫面的事件。

【主線程】的主要責(zé)任:

• 快速處理UI事件。而且只有它才處理UI事件, 其它線程還不能存取UI畫面上的對象(如TextView等),此時, 主線程就叫做UI線程。基本上,Android希望UI線程能根據(jù)用戶的要求做出快速響應(yīng),如果UI線程花太多時間處理后臺的工作,當(dāng)UI事件發(fā)生時,讓用戶等待時間超過5秒而未處理,Android系統(tǒng)就會給用戶顯示ANR提示信息。

只有UI線程才能執(zhí)行View派生類的onDraw()函數(shù)。

• 快速處理Broadcast消息。【主線程】除了處理UI事件之外,還要處理Broadcast消息。所以在BroadcastReceiver的onReceive()函數(shù)中,不宜占用太長的時間,否則導(dǎo)致【主線程】無法處理其它的Broadcast消息或UI事件。如果占用時間超過10秒, Android系統(tǒng)就會給用戶顯示ANR提示信息。

注意事項(xiàng):

• 盡量避免讓【主線程】執(zhí)行耗時的操作,讓它能快速處理UI事件和Broadcast消息。

• BroadcastReceiver的子類都是無狀態(tài)的,即每次啟動時,才會創(chuàng)建其對象,然后調(diào)用它的onReceive()函數(shù),當(dāng)執(zhí)行完onReceive()函數(shù)時,就立即刪除此對象。由于每次調(diào)用其函數(shù)時,會重新創(chuàng)建一個新的對象,所以對象里的屬性值,是無法讓各函數(shù)所共享。

一:線程通信、ActivityThread及Thread類是理解Android線程管理的關(guān)鍵。

線程,作為CPU調(diào)度資源的基本單位,在Android等針對嵌入式設(shè)備的操作系統(tǒng)中,有著非常重要和基礎(chǔ)的作用。本小節(jié)主要從以下三個方面進(jìn)行分析:

1.《Android線程管理――線程通信》
2.《Android線程管理――ActivityThread》
3.《Android線程管理――Thread類的內(nèi)部原理、休眠及喚醒》

--------------------------------------------------------------------------------

二、ActivityThread的主要工作及實(shí)現(xiàn)機(jī)制

ActivityThread是Android應(yīng)用的主線程(UI線程),說起ActivityThread,不得不提到Activity的創(chuàng)建、啟動過程以及ActivityManagerService,但本文將僅從線程管理的角度來分析ActivityThread。ActivityManagerService、ActivityStack、ApplicationThread等會在后續(xù)文章中詳細(xì)分析,敬請期待喔~~不過為了說清楚ActivityThread的由來,還是需要簡單介紹下。

以下引用自羅升陽大師的博客:《Android應(yīng)用程序的Activity啟動過程簡要介紹和學(xué)習(xí)計劃》

Step 1. 無論是通過Launcher來啟動Activity,還是通過Activity內(nèi)部調(diào)用startActivity接口來啟動新的Activity,都通過Binder進(jìn)程間通信進(jìn)入到ActivityManagerService進(jìn)程中,并且調(diào)用ActivityManagerService.startActivity接口;

Step 2. ActivityManagerService調(diào)用ActivityStack.startActivityMayWait來做準(zhǔn)備要啟動的Activity的相關(guān)信息;

Step 3. ActivityStack通知ApplicationThread要進(jìn)行Activity啟動調(diào)度了,這里的ApplicationThread代表的是調(diào)用ActivityManagerService.startActivity接口的進(jìn)程,對于通過點(diǎn)擊應(yīng)用程序圖標(biāo)的情景來說,這個進(jìn)程就是Launcher了,而對于通過在Activity內(nèi)部調(diào)用startActivity的情景來說,這個進(jìn)程就是這個Activity所在的進(jìn)程了;

Step 4. ApplicationThread不執(zhí)行真正的啟動操作,它通過調(diào)用ActivityManagerService.activityPaused接口進(jìn)入到ActivityManagerService進(jìn)程中,看看是否需要創(chuàng)建新的進(jìn)程來啟動Activity;

Step 5. 對于通過點(diǎn)擊應(yīng)用程序圖標(biāo)來啟動Activity的情景來說,ActivityManagerService在這一步中,會調(diào)用startProcessLocked來創(chuàng)建一個新的進(jìn)程,而對于通過在Activity內(nèi)部調(diào)用startActivity來啟動新的Activity來說,這一步是不需要執(zhí)行的,因?yàn)樾碌腁ctivity就在原來的Activity所在的進(jìn)程中進(jìn)行啟動;

Step 6. ActivityManagerServic調(diào)用ApplicationThread.scheduleLaunchActivity接口,通知相應(yīng)的進(jìn)程執(zhí)行啟動Activity的操作;

Step 7. ApplicationThread把這個啟動Activity的操作轉(zhuǎn)發(fā)給ActivityThread,ActivityThread通過ClassLoader導(dǎo)入相應(yīng)的Activity類,然后把它啟動起來。

大師的這段描述把ActivityManagerService、ActivityStack、ApplicationThread及ActivityThread的調(diào)用關(guān)系講的很清楚,本文將從ActivityThread的main()方法開始分析其主要工作及實(shí)現(xiàn)機(jī)制。

ActivityThread源碼來自:https://github.com/android/platform_frameworks_base/blob/master/core/java/android/app/ActivityThread.java

public static void main(String[] args) {Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");SamplingProfilerIntegration.start();// CloseGuard defaults to true and can be quite spammy. We// disable it here, but selectively enable it later (via// StrictMode) on debug builds, but using DropBox, not logs.CloseGuard.setEnabled(false);Environment.initForCurrentUser();// Set the reporter for event logging in libcoreEventLogger.setReporter(new EventLoggingReporter());AndroidKeyStoreProvider.install();// Make sure TrustedCertificateStore looks in the right place for CA certificatesfinal File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());TrustedCertificateStore.setDefaultUserDirectory(configDir);Process.setArgV0("<pre-initialized>");Looper.prepareMainLooper();ActivityThread thread = new ActivityThread();thread.attach(false);if (sMainThreadHandler == null) {sMainThreadHandler = thread.getHandler();}if (false) {Looper.myLooper().setMessageLogging(newLogPrinter(Log.DEBUG, "ActivityThread"));}// End of event ActivityThreadMain.Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);Looper.loop();throw new RuntimeException("Main thread loop unexpectedly exited");}

上述代碼中,紅色部分之前的代碼主要用于環(huán)境初始化、AndroidKeyStoreProvider安裝等,這里不做重點(diǎn)說明。紅色部分的代碼主要分為兩個功能塊:1)綁定應(yīng)用進(jìn)程到ActivityManagerService;2)主線程Handler消息處理。

關(guān)于線程通信機(jī)制,Handler、MessageQueue、Message及Looper四者的關(guān)系請參考上一篇文章《Android線程管理――線程通信》。

2.1 應(yīng)用進(jìn)程綁定

main()方法通過thread.attach(false)綁定應(yīng)用進(jìn)程。ActivityManagerNative通過getDefault()方法返回ActivityManagerService實(shí)例,ActivityManagerService通過attachApplication將ApplicationThread對象綁定到ActivityManagerService,而ApplicationThread作為Binder實(shí)現(xiàn)ActivityManagerService對應(yīng)用進(jìn)程的通信和控制。

private void attach(boolean system) {sCurrentActivityThread = this;mSystemThread = system;if (!system) {…… RuntimeInit.setApplicationObject(mAppThread.asBinder());final IActivityManager mgr = ActivityManagerNative.getDefault();try {mgr.attachApplication(mAppThread);} catch (RemoteException ex) {// Ignore}…… } else {……}}

在ActivityManagerService內(nèi)部,attachApplication實(shí)際是通過調(diào)用attachApplicationLocked實(shí)現(xiàn)的,這里采用了synchronized關(guān)鍵字保證同步。

@Overridepublic final void attachApplication(IApplicationThread thread) {synchronized (this) {int callingPid = Binder.getCallingPid();final long origId = Binder.clearCallingIdentity();attachApplicationLocked(thread, callingPid);Binder.restoreCallingIdentity(origId);}}

attachApplicationLocked的實(shí)現(xiàn)較為復(fù)雜,其主要功能分為兩部分:

thread.bindApplication
mStackSupervisor.attachApplicationLocked(app)

private final boolean attachApplicationLocked(IApplicationThread thread,int pid) {// Find the application record that is being attached... either via// the pid if we are running in multiple processes, or just pull the// next app record if we are emulating process with anonymous threads.ProcessRecord app;if (pid != MY_PID && pid >= 0) {synchronized (mPidsSelfLocked) {app = mPidsSelfLocked.get(pid);}} else {app = null;}// ……try {// ……thread.bindApplication(processName, appInfo, providers, app.instrumentationClass,profilerInfo, app.instrumentationArguments, app.instrumentationWatcher,app.instrumentationUiAutomationConnection, testMode, enableOpenGlTrace,enableTrackAllocation, isRestrictedBackupMode || !normalMode, app.persistent,new Configuration(mConfiguration), app.compat,getCommonServicesLocked(app.isolated),mCoreSettingsObserver.getCoreSettingsLocked());updateLruProcessLocked(app, false, null);app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();} catch (Exception e) {// todo: Yikes! What should we do? For now we will try to// start another process, but that could easily get us in// an infinite loop of restarting processes...Slog.wtf(TAG, "Exception thrown during bind of " + app, e);app.resetPackageList(mProcessStats);app.unlinkDeathRecipient();startProcessLocked(app, "bind fail", processName);return false;}// See if the top visible activity is waiting to run in this process...if (normalMode) {try {if (mStackSupervisor.attachApplicationLocked(app)) {didSomething = true;}} catch (Exception e) {Slog.wtf(TAG, "Exception thrown launching activities in " + app, e);badApp = true;}}// ……}

thread對象其實(shí)是ActivityThread里ApplicationThread對象在ActivityManagerService的代理對象,故此執(zhí)行thread.bindApplication,最終會調(diào)用ApplicationThread的bindApplication方法。該bindApplication方法的實(shí)質(zhì)是通過向ActivityThread的消息隊列發(fā)送BIND_APPLICATION消息,消息的處理調(diào)用handleBindApplication方法,handleBindApplication方法比較重要的是會調(diào)用如下方法:

mInstrumentation.callApplicationOnCreate(app);

callApplicationOnCreate即調(diào)用應(yīng)用程序Application的onCreate()方法,說明Application的onCreate()方法會比所有activity的onCreate()方法先調(diào)用。

mStackSupervisor為ActivityManagerService的成員變量,類型為ActivityStackSupervisor。

/** Run all ActivityStacks through this */
ActivityStackSupervisor mStackSupervisor;

從注釋可以看出,mStackSupervisor為Activity堆棧管理輔助類實(shí)例。ActivityStackSupervisor的attachApplicationLocked()方法的調(diào)用了realStartActivityLocked()方法,在realStartActivityLocked()方法中,會調(diào)用scheduleLaunchActivity()方法:

final boolean realStartActivityLocked(ActivityRecord r,ProcessRecord app, boolean andResume, boolean checkConfig)throws RemoteException {//... try {//...app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,System.identityHashCode(r), r.info,new Configuration(mService.mConfiguration),r.compat, r.icicle, results, newIntents, !andResume,mService.isNextTransitionForward(), profileFile, profileFd,profileAutoStop);//...} catch (RemoteException e) {//...}//... return true;}

app.thread也是ApplicationThread對象在ActivityManagerService的一個代理對象,最終會調(diào)用ApplicationThread的scheduleLaunchActivity方法。

// we use token to identify this activity without having to send the// activity itself back to the activity manager. (matters more with ipc)@Overridepublic 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();……sendMessage(H.LAUNCH_ACTIVITY, r);}

同bindApplication()方法,最終是通過向ActivityThread的消息隊列發(fā)送消息,在ActivityThread完成實(shí)際的LAUNCH_ACTIVITY的操作。

public void handleMessage(Message msg) {if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));switch (msg.what) {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);Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);} break;……}

handleLaunchActivity()用于啟動Activity。具體的啟動流程不在這里詳述了,這里重點(diǎn)說明ApplicationThread及ActivityThread的線程通信機(jī)制。

2.2 主線程消息處理

在《Android線程管理――線程通信》中談到了普通線程中Handler、MessageQueue、Message及Looper四者的關(guān)系,那么,ActivityThread中的線程通信又有什么不同呢?不同之處主要表現(xiàn)為兩點(diǎn):1)Looper的初始化方式;2)Handler生成。

首先,ActivityThread通過Looper.prepareMainLooper()初始化Looper,為了直觀比較ActivityThread與普通線程初始化Looper的區(qū)別,把兩種初始化方法放在一起:

/** Initialize the current thread as a looper.* This gives you a chance to create handlers that then reference* this looper, before actually starting the loop. Be sure to call* {@link #loop()} after calling this method, and end it by calling* {@link #quit()}.*/public static void prepare() {prepare(true);}private static void prepare(boolean quitAllowed) {if (sThreadLocal.get() != null) {throw new RuntimeException("Only one Looper may be created per thread");}sThreadLocal.set(new Looper(quitAllowed));}/*** Initialize the current thread as a looper, marking it as an* application's main looper. The main looper for your application* is created by the Android environment, so you should never need* to call this function yourself. See also: {@link #prepare()}*/public static void prepareMainLooper() {prepare(false);synchronized (Looper.class) {if (sMainLooper != null) {throw new IllegalStateException("The main Looper has already been prepared.");}sMainLooper = myLooper();}}

•普通線程的prepare()方法默認(rèn)quitAllowed參數(shù)為true,表示允許退出,ActivityThread在prepareMainLooper()方法中調(diào)用prepare()方法,參數(shù)為false,表示主線程不允許退出。
•普通線程只調(diào)用prepare()方法,ActivityThread在調(diào)用完prepare()方法之后,會通過myLooper()方法將本地線程<ThreadLocal>的Looper對象的引用交給sMainLooper。myLooper()其實(shí)就是調(diào)用sThreadLocal的get()方法實(shí)現(xiàn)的。

/*** Return the Looper object associated with the current thread. Returns* null if the calling thread is not associated with a Looper.*/public static Looper myLooper() {return sThreadLocal.get();}

•之所以要通過sMainLooper指向ActivityThread的Looper對象,就是希望通過getMainLooper()方法將主線程的Looper對象開放給其他線程。

/** Returns the application's main looper, which lives in the main thread of the application.*/public static Looper getMainLooper() {synchronized (Looper.class) {return sMainLooper;}}

其次,ActivityThread與普通線程的Handler生成方式也不一樣。普通線程生成一個與Looper綁定的Handler即可,ActivityThread通過sMainThreadHandler指向getHandler()的返回值,而getHandler()方法返回的其實(shí)是一個繼承Handler的H對象。。

private class H extends Handler {……}final H mH = new H();final Handler getHandler() {return mH;}

真正實(shí)現(xiàn)消息機(jī)制“通”信的其實(shí)是Looper的loop()方法,loop()方法的核心實(shí)現(xiàn)如下:

/*** Run the message queue in this thread. Be sure to call* {@link #quit()} to end the loop.*/public static void loop() {final Looper me = myLooper();if (me == null) {throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");}final MessageQueue queue = me.mQueue;// Make sure the identity of this thread is that of the local process,// and keep track of what that identity token actually is.Binder.clearCallingIdentity();final long ident = Binder.clearCallingIdentity();for (;;) {Message msg = queue.next(); // might blockif (msg == null) {// No message indicates that the message queue is quitting.return;}// This must be in a local variable, in case a UI event sets the loggerPrinter logging = me.mLogging;if (logging != null) {logging.println(">>>>> Dispatching to " + msg.target + " " +msg.callback + ": " + msg.what);}msg.target.dispatchMessage(msg);if (logging != null) {logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);}// Make sure that during the course of dispatching the// identity of the thread wasn't corrupted.final long newIdent = Binder.clearCallingIdentity();if (ident != newIdent) {Log.wtf(TAG, "Thread identity changed from 0x"+ Long.toHexString(ident) + " to 0x"+ Long.toHexString(newIdent) + " while dispatching to "+ msg.target.getClass().getName() + " "+ msg.callback + " what=" + msg.what);}msg.recycle();}}

大致流程如下:

•首先通過上述myLooper()方法獲取Looper對象,取出Looper持有的MessageQueue;
•然后從MessageQueue取出Message,如果Message為null,說明線程正在退出;
•Message不為空,則調(diào)用Message的target handler對該Message進(jìn)行分發(fā),具體分發(fā)、處理流程可參考《Android線程管理――線程通信》;
•消息處理完畢,調(diào)用recycle()方法進(jìn)行回收。

發(fā)表評論 共有條評論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 陆川县| 吉安市| 都兰县| 兴海县| 五大连池市| 渭南市| 平江县| 华安县| 黔江区| 昌吉市| 响水县| 莆田市| 综艺| 积石山| 门头沟区| 德钦县| 安义县| 侯马市| 历史| 婺源县| 乐都县| 商河县| 益阳市| 沙坪坝区| 皮山县| 东乌珠穆沁旗| 奎屯市| 拜城县| 禄劝| 赤城县| 额尔古纳市| 大港区| 江油市| 英山县| 哈尔滨市| 海宁市| 微山县| 大渡口区| 刚察县| 库车县| 乐业县|