Android开发经验谈Android开发Android技术知识

Handler使用场景以及源码分析

2018-01-18  本文已影响150人  姜康

路漫漫其修远兮,吾将上下而求索

Handler的使用场景


然后在子线程操作(这里的操作是判断该线程是否是主线程)完成之后,通知主线程:

private fun checkIsMainThread() {
     thread {
         val message = Message()
         message.what = MSG_WHAT
         message.obj = isMainThread()
         mHandler.sendMessage(message)
     }.start()
 }

有时候我们需要判断当前线程是否是主线程,这个时候就可以用带Looper了,通过Looper,我们就可以知道当前线程是否为主线程:

    private fun isMainThread(): Boolean {
        return Looper.myLooper() == Looper.getMainLooper()
    }
   private fun directUpdateUI() {
        thread {
            Thread.sleep(1000)
            Handler(Looper.getMainLooper()).post {
                btnDirectUpdateUI.text = "UI已经更新了"
            }
        }.start()
    }

当然,这个方法也可以用在两个子线程之间的通信上。

 public final void runOnUiThread(Runnable action) {
        if (Thread.currentThread() != mUiThread) {
            mHandler.post(action);
        } else {
            action.run();
        }
    }

这里的mHandler是在主线程中创建的,如果当前线程不是主线程,则利用主线程的Handler进行post操作,如果是主线程,则直接执行。

源码解析


这里首先看看Looper中的ThreadLocal中有没有存Looper实例,如果没有,则新建一个该线程的Looper实例。ThreadLocal可以看做是一个存储线程私有变量的数据结构,简单的就get和set方法,这里不详述了。

这里如果要接收Message并执行一定的操作,就必须重写handleMessage方法,因为Handler源码中这个方法是一个空方法。

  /**
   * Subclasses must implement this to receive messages.
   */
  public void handleMessage(Message msg) {
  }

然后来看一下Handler的构造函数:

 public Handler() {
     this(null, false);
 }

 public Handler(Callback callback, boolean async) {
     //省略部分代码
     //获取当前线程的Looper
     mLooper = Looper.myLooper();
     //如果当前线程没有Looper,抛出异常
     if (mLooper == null) {
         throw new RuntimeException(
             "Can't create handler inside thread that has not called Looper.prepare()");
     }
     //初始化操作
     mQueue = mLooper.mQueue;
     mCallback = callback;
     mAsynchronous = async;
 }

从上面代码可以看出,如果要在一个线程中创建Handler,一定要先执行Looper.prepare()方法,创建一个Looper实例,不然会抛出异常。
这里可能会有一个疑问,我们在主线程中创建Handler的时候并没有执行Looper.prepare()方法啊,为什么可以正常执行?
答案是主线程其实在很早之前就已经创建了Looper实例,具体的可以参考ActivityThread这个类中的main方法,具体的这里就不讲了:

    public static void main(String[] args) {
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
        SamplingProfilerIntegration.start();
        CloseGuard.setEnabled(false);
        Environment.initForCurrentUser();
        EventLogger.setReporter(new EventLoggingReporter());
        final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
        TrustedCertificateStore.setDefaultUserDirectory(configDir);
        Process.setArgV0("<pre-initialized>");

        //在这里创建主线程Looper
        Looper.prepareMainLooper();

        ActivityThread thread = new ActivityThread();
        thread.attach(false);

        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }

        if (false) {
            Looper.myLooper().setMessageLogging(new
                    LogPrinter(Log.DEBUG, "ActivityThread"));
        }
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        //开始消息队列循环
        Looper.loop();

        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

上面代码中创建主线程的Looper,看一下具体代码:

/**
     * 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();
        }
    }

正如前面所说,我们还可以传入一个Looper实例到Handler的构造函数中,用来直接切换到主线程执行,或者切换到别的线程执行代码,来看看源码:

 /**
   * Use the provided {@link Looper} instead of the default one.
   *
   * @param looper The looper, must not be null.
   */
  public Handler(Looper looper) {
      this(looper, null, false);
  }
  
   public Handler(Looper looper, Callback callback, boolean async) {
      mLooper = looper;
      mQueue = looper.mQueue;
      mCallback = callback;
      mAsynchronous = async;
  }
  

就是将传入的Looper实例赋值给mLooper。mQueue则是取得mLooper的消息队列。

/**
    * 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;

       for (;;) {
           //从消息队列中取出消息
           Message msg = queue.next(); // might block
           if (msg == null) {
               // No message indicates that the message queue is quitting.
               return;
           }

           //...
          
           try {
                   //分发消息
               msg.target.dispatchMessage(msg);
           } finally {
               if (traceTag != 0) {
                   Trace.traceEnd(traceTag);
               }
           }

           msg.recycleUnchecked();
       }
   }

这里从Looper持有的消息队列对象中循环取出消息,然后利用msg.target.dispatchMessage(msg)进行消息分发,这里的msg.target其实就是Handler,然后执行Handler的dispatchMesage方法.

总结


从一个非主线程创建Handler对于分析Handler的流程将会更加直观,这里梳理一下流程:

上一篇 下一篇

猜你喜欢

热点阅读