zoukankan      html  css  js  c++  java
  • 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线程的消息队列。

      

  • 相关阅读:
    灵魂有香气的女子IOS版本APP,近期将考虑开放源代码
    PHP中$_SERVER获取当前页面的完整URL地址
    zabbix监控报错zabbix server is not running解决方法
    Linux重启inotify配置max_user_watches无效被恢复默认值8192的正确修改方法
    centos在yum install报错:Another app is currently holding the yum lock解决方法
    nginx去掉单个目录和多个目录PHP执行权限方法
    express搭建权限管理系统
    在express项目中使用formidable & multiparty实现文件上传
    vue生成图片验证码
    第0步:OracleRAC软件准备
  • 原文地址:https://www.cnblogs.com/naray/p/15293606.html
Copyright © 2011-2022 走看看