Android之UI執行緒啟動
一、UI執行緒是什麼?
UI執行緒就是重新整理UI的執行緒。
二、UI執行緒是不是主執行緒?
主執行緒何時啟動
在應用啟動時AMS請求Zygout程序啟動應用程序,在應用程序啟動後的第一條執行緒就是主執行緒,執行緒啟動後執行ActivityThread.main()函式,在main()函式中啟動的主執行緒Looper。
public static void main(String[] args) { …… Looper.prepareMainLooper(); …… if (sMainThreadHandler == null) { sMainThreadHandler= thread.getHandler(); } …… Looper.loop(); …… }
在子執行緒重新整理Ui通過使用Activity.runOnUiThread()函式和View.post()函式實現,分別看看這兩個函式的實現:
/** * Runs the specified action on the UI thread. If the current thread is the UI * thread, then the action is executed immediately. If the current thread is * not the UI thread, the action is posted to the event queue of the UI thread. * *@param action the action to run on the UI thread */ public final void runOnUiThread(Runnable action) { if (Thread.currentThread() != mUiThread) { mHandler.post(action); } else { action.run(); } }
Runs the specified action on the UI thread. If the current thread is the UIthread, then the action is executed immediately. If the current thread isnot the UI thread, the action is posted to the event queue of the UI thread.
這段註釋大概意思是action是在Ui執行緒執行的特定的runnable,如果,呼叫runOnUiThread()函式的執行緒是Ui執行緒,action的Runnable會立即執行。如果,呼叫runOnUiThread()函式不是Ui執行緒,action的Runnable會新增到Ui執行緒的訊息佇列。
當前呼叫runOnUiThread()函式的執行緒不是Ui執行緒,通過mHandler將action新增到Ui執行緒的訊息佇列,下面看看mHandler是什麼時間初始化?
public class Activity extends ContextThemeWrapper implements LayoutInflater.Factory2, Window.Callback, KeyEvent.Callback, OnCreateContextMenuListener, ComponentCallbacks2, Window.OnWindowDismissedCallback, AutofillManager.AutofillClient, ContentCaptureManager.ContentCaptureClient { …… // we must have a handler before the FragmentController is constructed @UnsupportedAppUsage final Handler mHandler = new Handler(); …… }
mHandler是在Activity建立的時候初始化的,在Activity啟動過程一文中有說到,Activity建立是通過AMS使用ApplicationThread(Binder)物件與應用IPC通訊,呼叫ApplicationThread.scheduleLaunchActivity()函式嚮應用的主執行緒訊息佇列傳送訊息。在主執行緒中呼叫handleLaunchActivity()函式建立Activity物件。
mHandler初始化是直接new Handler(),沒有傳入Looper引數,那麼,mHander傳送訊息對應的訊息佇列就是主執行緒的訊息佇列。而runOnUiThread()的Runnable的Action是在Ui執行緒執行。那麼,Ui執行緒其實就是主執行緒。
View.post()函式實現:
/** * <p>Causes the Runnable to be added to the message queue. * The runnable will be run on the user interface thread.</p> * * @param action The Runnable that will be executed. * * @return Returns true if the Runnable was successfully placed in to the * message queue. Returns false on failure, usually because the * looper processing the message queue is exiting. * * @see #postDelayed * @see #removeCallbacks */ public boolean post(Runnable action) { final AttachInfo attachInfo = mAttachInfo; if (attachInfo != null) { return attachInfo.mHandler.post(action); } // Postpone the runnable until we know on which thread it needs to run. // Assume that the runnable will be successfully placed after attach. getRunQueue().post(action); return true; }
Causes the Runnable to be added to the message queue. The runnable will be run on the user interface thread.
這段註釋大概的意思是Runnable將新增到訊息佇列,而Runnable將在使用者執行緒執行。
上面程式碼做了兩件事:
1. 在View建立時間mAttachInfo還沒設定,會將Runnable暫時儲存在View內部的訊息佇列中,當前View的mAttachInfo設定完了,再將訊息新增到使用者執行緒的訊息佇列。
2. 直接將訊息新增到使用者執行緒的訊息佇列中。
那麼,使用者執行緒是不是Ui執行緒(主執行緒)。
首先,確認mAttachInfo是什麼時候建立的,mAttachInfo是在ViewRootImpl建構函式裡建立的,mHandler也是從ViewRootImpl的成員變數。
public final class ViewRootImpl implements ViewParent, View.AttachInfo.Callbacks, ThreadedRenderer.DrawCallbacks { public ViewRootImpl(Context context, Display display, IWindowSession session, boolean useSfChoreographer) { final ViewRootHandler mHandler = new ViewRootHandler(); @UnsupportedAppUsage final View.AttachInfo mAttachInfo; …… mAttachInfo = new View.AttachInfo(mWindowSession, mWindow, display, this, mHandler, this, context); …… } }
mHandler在ViewRootImpl建立時初始化的,mHandler對應的訊息佇列也就是ViewRootImpl建立所線上程的訊息佇列。
ViewRootImpl是什麼時候建立的,ViewRootImpl是View在新增到View時建立的。通過WindowManagerGlobl.addVie()函式建立的。
public final class WindowManagerGlobal { …… public void addView(View view, ViewGroup.LayoutParams params, Display display, Window parentWindow, int userId) { ViewRootImpl root; …… root = new ViewRootImpl(view.getContext(), display); } …… }
Window是在Activity.attach()函式建立的,也就是說Window在Ui執行緒建立的,addView()函式也是Ui執行緒呼叫的函式。那麼,推匯出ViewRootImpl是Ui執行緒建立的,mHandler對應的訊息佇列也是Ui執行緒的訊息佇列。