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 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. 

  这段注释大概意思是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线程的消息队列。

  

 

posted @ 2021-09-16 18:28  naray  阅读(741)  评论(0编辑  收藏  举报