Android 中的消息机制

Posted by JH on July 6, 2021

典型案例分析

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    mTextView = findViewById(R.id.textView1);

    // Restore TextView if there is a savedInstanceState bundle.
    if (savedInstanceState != null) {
        mTextView?.text = savedInstanceState.getString(TEXT_STATE);
    }

    mCountdown = findViewById(R.id.countdown)

    Thread {
        for (i in 5 downTo 1) {
            mCountdown?.text = i.toString()
            try {
                Thread.sleep(1000)
            } catch (e: InterruptedException) {
                e.printStackTrace()
            }
        }
        //计时结束后跳转到其他界面
        startActivity(Intent(this, SubActivity::class.java))
    }.start()
}

这段代码似乎看上去很正常,但是当你运行时就会发现,它会报一个致命性的异常:

ERROR/AndroidRuntime(421): FATAL EXCEPTION: Thread-8
ERROR/AndroidRuntime(421): android.view.ViewRoot$CalledFromWrongThreadException: 
    Only the original thread that created a view hierarchy can touch its views.

原因在于,Android 系统中的 UI 组件并不是线程安全的,如果要更新 UI,必须在主线程中更新,不可以在子线程中执行更新的操作。

既然这样,我们就要在子线程中通知主线程,让主线程做更新操作。我们即需要使用到 Handler 对象通知主线程。

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    mTextView = findViewById(R.id.textView1);

    // Restore TextView if there is a savedInstanceState bundle.
    if (savedInstanceState != null) {
        mTextView?.text = savedInstanceState.getString(TEXT_STATE);
    }

    mCountdown = findViewById(R.id.countdown)

    Thread {
        for (i in 5 downTo 1) {
//                mCountdown?.text = i.toString()
            val msg = Message()
            msg.arg1 = i
            handler1.sendMessage(msg)

            try {
                Thread.sleep(1000)
            } catch (e: InterruptedException) {
                e.printStackTrace()
            }
        }
        //计时结束后跳转到其他界面
        startActivity(Intent(this, SubActivity::class.java))
    }.start()
}

//消息处理者,创建一个Handler的子类对象,目的是重写Handler的处理消息的方法(handleMessage())
private val handler1: Handler = object : Handler() {
    override fun handleMessage(msg: Message) {
        mCountdown?.text = msg.arg1.toString()
    }
}

通过上面这种方式,我们就可以解决线程安全的问题,把复杂的任务处理工作交给子线程去完成, 然后子线程通过 handler 对象告知主线程,由主线程更新视图,这个过程中消息机制起着重要的作用。

Handler 消息机制

Handler 用来发送和处理线程对应的消息队列 MessageQueue 中存储的 Message。每个 Handler 实例对应一个线程以及该线程的消息队列。 当你创建一个新的 Handler,它会绑定创建它的线程和消息队列,然后它会向消息队列发送 Message 或者 Runnable,并且在它们离开消息队列时执行。

构造函数

Handler 的构造函数大致上可以分为两类,先来看第一类:

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

public Handler(Callback callback) {
    this(callback, false);
}

public Handler(Callback callback, boolean async) {
    // 如果是匿名类、内部类、本地类,且没有使用 static 修饰符,提示可能导致内存泄漏
    if (FIND_POTENTIAL_LEAKS) {
        final Class<? extends Handler> klass = getClass();
        if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
                (klass.getModifiers() & Modifier.STATIC) == 0) {
            Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
                klass.getCanonicalName());
        }
    }

    // 从当前线程的 ThreadLocal获取 Looper
    mLooper = Looper.myLooper();
    if (mLooper == null) {  // 创建 Handler 之前一定要先创建 Looper。主线程已经自动为我们创建。
        throw new RuntimeException(
            "Can't create handler inside thread " + Thread.currentThread()
                    + " that has not called Looper.prepare()");
    }
    mQueue = mLooper.mQueue; // Looper 持有一个 MessageQueue
    mCallback = callback; // handleMessage 回调
    mAsynchronous = async; // 是否异步处理
}

这一类构造函数最终调用的都是两个参数的方法,参数中不传递 Looper,所以要显式检查是否已经创建 Looper。 创建 Handler 之前一定要先创建 Looper,否则会直接抛出异常。在主线程中 Looper 已经自动创建好,无需我们手动创建,在 ActivityThread.java 的 main() 方法中可以看到。 Looper 持有一个消息队列 MessageQueue,并赋值给 Handler 中的 mQueue 变量。

Callback 是一个接口,定义如下:

public interface Callback {
    public boolean handleMessage(Message msg);
}

可以看到,Handler 处理消息还可以通过构造器参数传入 CallBack 的方式。

看过 Handler 的第一类构造函数,第二类其实就很简单了,只是多了 Looper 参数而已:

public Handler(Looper looper) {
    this(looper, null, false);
}
    
public Handler(Looper looper, Callback callback) {
    this(looper, callback, false);
}
    
public Handler(Looper looper, Callback callback, boolean async) {
    mLooper = looper;
    mQueue = looper.mQueue;
    mCallback = callback;
    mAsynchronous = async;
}

发送消息

  1. 几乎所有的 sendXXX() 最后调用的都是 sendMessageAtTime() 方法。

     sendMessage(Message msg);//立刻发送消息
     sendMessageAtTime(Message msg, long atTime);//在某个时间点发送消息
     sendMessageDelayed(Message msg, long delayedTime);//在当前时间点延迟一段时间发送消息
    
  2. 所有的 postXXX() 方法都是调用 getPostMessage() 将 参数中的 Runnable 包装成 Message,再调用对应的 sendXXX() 方法。

     private static Message getPostMessage(Runnable r) {
         Message m = Message.obtain();
         m.callback = r;
         return m;
     }
        
     private static Message getPostMessage(Runnable r, Object token) {
         Message m = Message.obtain();
         m.obj = token;
         m.callback = r;
         return m;
     }
    
  3. 殊途同归,发送消息的重任最后都落在了 sendMessageAtTime() 身上。

     public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
         MessageQueue queue = mQueue;
         if (queue == null) {
             RuntimeException e = new RuntimeException(
                     this + " sendMessageAtTime() called with no mQueue");
             Log.w("Looper", e.getMessage(), e);
             return false;
         }
         return enqueueMessage(queue, msg, uptimeMillis);
     }
            
     private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
         msg.target = this;
         if (mAsynchronous) {
             msg.setAsynchronous(true);
         }
         return queue.enqueueMessage(msg, uptimeMillis); // 调用 Messagequeue 的 enqueueMessage() 方法
     }   
    

    可以看到 Handler 把发送消息的任务转手又交给了 MessageQueue 来处理。

  4. MessageQueue

    Message 的入队工作实际上是由 MessageQueue 通过 enqueueMessage() 函数来完成的。

     boolean enqueueMessage(Message msg, long when) {
         if (msg.target == null) { // msg 必须有 target
             throw new IllegalArgumentException("Message must have a target.");
         }
         if (msg.isInUse()) { // msg 不能正在被使用
             throw new IllegalStateException(msg + " This message is already in use.");
         }
        
         synchronized (this) {
             if (mQuitting) { // 正在退出,回收消息并直接返回
                 IllegalStateException e = new IllegalStateException(
                         msg.target + " sending message to a Handler on a dead thread");
                 Log.w(TAG, e.getMessage(), e);
                 msg.recycle();
                 return false;
             }
        
             msg.markInUse();
             msg.when = when;
             Message p = mMessages;
             boolean needWake;
             if (p == null || when == 0 || when < p.when) {
                 // New head, wake up the event queue if blocked.
                 // 插入消息队列头部,需要唤醒队列
                 msg.next = p;
                 mMessages = msg;
                 needWake = mBlocked;
             } else {
                 // Inserted within the middle of the queue.  Usually we don't have to wake
                 // up the event queue unless there is a barrier at the head of the queue
                 // and the message is the earliest asynchronous message in the queue.
                 needWake = mBlocked && p.target == null && msg.isAsynchronous();
                 Message prev;
                 for (;;) {
                     prev = p;
                     p = p.next;
                     if (p == null || when < p.when) { // 按消息的触发时间顺序插入队列
                         break;
                     }
                     if (needWake && p.isAsynchronous()) {
                         needWake = false;
                     }
                 }
                 msg.next = p; // invariant: p == prev.next
                 prev.next = msg;
             }
        
             // We can assume mPtr != 0 because mQuitting is false.
             if (needWake) {
                 nativeWake(mPtr);
             }
         }
         return true;
     }
    

    可以看出来,MessageQueue 是用链表结构来存储消息的,消息是按触发时间的顺序来插入的。 enqueueMessage() 方法是用来存消息的,而取靠的是 next() 方法。

  5. next()

     Message next() {
         // Return here if the message loop has already quit and been disposed.
         // This can happen if the application tries to restart a looper after quit
         // which is not supported.
         final long ptr = mPtr;
         if (ptr == 0) {
             return null;
         }
        
         int pendingIdleHandlerCount = -1; // -1 only during first iteration
         int nextPollTimeoutMillis = 0;
         for (;;) {
             if (nextPollTimeoutMillis != 0) {
                 Binder.flushPendingCommands();
             }
        
             // 阻塞方法,主要是通过 native 层的 epoll 监听文件描述符的写入事件来实现的。
             // 如果 nextPollTimeoutMillis = -1,一直阻塞不会超时。
             // 如果 nextPollTimeoutMillis = 0,不会阻塞,立即返回。
             // 如果 nextPollTimeoutMillis > 0,最长阻塞nextPollTimeoutMillis毫秒(超时),如果期间有程序唤醒会立即返回。
             nativePollOnce(ptr, nextPollTimeoutMillis);
        
             synchronized (this) {
                 // Try to retrieve the next message.  Return if found.
                 final long now = SystemClock.uptimeMillis();
                 Message prevMsg = null;
                 Message msg = mMessages;
                 if (msg != null && msg.target == null) {
                     // Stalled by a barrier.  Find the next asynchronous message in the queue.
                     // msg.target == null表示此消息为消息屏障(通过postSyncBarrier方法发送来的)
                     // 如果发现了一个消息屏障,会循环找出第一个异步消息(如果有异步消息的话),
                     // 所有同步消息都将忽略(平常发送的一般都是同步消息)
                     do {
                         prevMsg = msg;
                         msg = msg.next;
                     } while (msg != null && !msg.isAsynchronous());
                 }
                 if (msg != null) {
                     if (now < msg.when) {
                         // 消息触发时间未到,设置下一次轮询的超时时间
                         // Next message is not ready.  Set a timeout to wake up when it is ready.
                         nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                     } else {
                         // Got a message.
                         mBlocked = false;
                         if (prevMsg != null) {
                             prevMsg.next = msg.next;
                         } else {
                             mMessages = msg.next;
                         }
                         msg.next = null;
                         if (DEBUG) Log.v(TAG, "Returning message: " + msg);
                         msg.markInUse(); // 标记 FLAG_IN_USE
                         return msg;
                     }
                 } else {
                     // No more messages.
                     // 没有消息,会一直阻塞,直到被唤醒
                     nextPollTimeoutMillis = -1;
                 }
        
                 // Process the quit message now that all pending messages have been handled.
                 if (mQuitting) {
                     dispose();
                     return null;
                 }
        
                 // If first time idle, then get the number of idlers to run.
                 // Idle handles only run if the queue is empty or if the first message
                 // in the queue (possibly a barrier) is due to be handled in the future.
                 // Idle handle 仅当队列为空或者队列中的第一个消息将要执行时才会运行
                 if (pendingIdleHandlerCount < 0
                         && (mMessages == null || now < mMessages.when)) {
                     pendingIdleHandlerCount = mIdleHandlers.size();
                 }
                 if (pendingIdleHandlerCount <= 0) {
                     // No idle handlers to run.  Loop and wait some more.
                     // 没有 idle handler 需要运行,继续循环
                     mBlocked = true;
                     continue;
                 }
        
                 if (mPendingIdleHandlers == null) {
                     mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
                 }
                 mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
             }
        
             // Run the idle handlers.
             // We only ever reach this code block during the first iteration.
             // 只有第一次循环时才会执行下面的代码块
             for (int i = 0; i < pendingIdleHandlerCount; i++) {
                 final IdleHandler idler = mPendingIdleHandlers[i];
                 mPendingIdleHandlers[i] = null; // release the reference to the handler
        
                 boolean keep = false;
                 try {
                     keep = idler.queueIdle();
                 } catch (Throwable t) {
                     Log.wtf(TAG, "IdleHandler threw exception", t);
                 }
        
                 if (!keep) {
                     synchronized (this) {
                         mIdleHandlers.remove(idler);
                     }
                 }
             }
        
             // Reset the idle handler count to 0 so we do not run them again.
             // 将 pendingIdleHandlerCount 置零保证不再运行
             pendingIdleHandlerCount = 0;
        
             // While calling an idle handler, a new message could have been delivered
             // so go back and look again for a pending message without waiting.
             nextPollTimeoutMillis = 0;
         }
     }
    

    next() 方法是一个死循环,但是当没有消息的时候会阻塞,避免过度消耗 CPU。nextPollTimeoutMillis 大于 0 时表示等待下一条消息需要阻塞的时间。等于 -1 时表示没有消息了,一直阻塞到被唤醒。 这里的阻塞主要靠 native 函数 nativePollOnce() 来完成。可以看Gityuan博客【Android消息机制2-Handler(Native层)】

Looper

创建 Handler 之前必须先创建 Looper,而主线程已经为我们自动创建了 Looper,无需再手动创建,见 ActivityThread.java 的 main() 方法:

public static void main(String[] args) {
...
 Looper.prepareMainLooper(); // 创建主线程 Looper
...
}
  • prepareMainLooper()

      public static void prepareMainLooper() {
          prepare(false);
          synchronized (Looper.class) {
              if (sMainLooper != null) {
                  throw new IllegalStateException("The main Looper has already been prepared.");
              }
              sMainLooper = myLooper();
          }
      }
    

    可以注意到 sMainLooper 只能被初始化一次,也就是说 prepareMainLooper() 只能调用一次,否则将直接抛出异常。

  • prepare()

      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));
      }
    

    需要注意主线程中调用的是 prepare(false),说明主线程 Looper 是不允许退出的。因为主线程需要源源不断的处理各种事件,一旦退出,系统也就瘫痪了。 而我们在子线程调用 prepare() 来初始化 Looper时,默认调动的是 prepare(true),子线程 Looper 是允许退出的。

    每个线程的 Looper 是通过 ThreadLocal 来存储的,保证其线程私有。回顾文章开头介绍的 Handler 的构造函数中 mLooper 变量的初始化:

      mLooper = Looper.myLooper();
        
      public static @Nullable Looper myLooper() {
          // 通过当前线程的 ThreadLocal 来获取
          return sThreadLocal.get();
      }
    
  • 构造函数
      private Looper(boolean quitAllowed) {
          mQueue = new MessageQueue(quitAllowed);
          mThread = Thread.currentThread();
      }
    

    对照 Handler 的构造函数:

      public Handler(Looper looper, Callback callback, boolean async) {
          mLooper = looper;
          mQueue = looper.mQueue;
          mCallback = callback;
          mAsynchronous = async;
      }
    

    其中的关系就很清晰了:

    • Looper 持有 MessageQueue 对象的引用
    • Handler 持有 Looper 对象的引用以及 Looper 对象的 MessageQueue 的引用
  • loop()

    子线程使用 Handler 的标准写法:

      class LooperThread extends Thread {
          public Handler mHandler;
          
          public void run() {
              Looper.prepare();
          
              mHandler = new Handler() {
                  public void handleMessage(Message msg) {
                      // process incoming messages here
                  }
              };
          
              Looper.loop();
          }
      }
    

    让消息队列转起来的核心就是 Looper.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.");
          }
          if (me.mInLoop) {
              Slog.w(TAG, "Loop again would have the queued messages be executed"
                      + " before this one completed.");
          }
        
          me.mInLoop = true;
          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();
        
          // Allow overriding a threshold with a system prop. e.g.
          // adb shell 'setprop log.looper.1000.main.slow 1 && stop && start'
          final int thresholdOverride =
                  SystemProperties.getInt("log.looper."
                          + Process.myUid() + "."
                          + Thread.currentThread().getName()
                          + ".slow", 0);
        
          boolean slowDeliveryDetected = false;
        
          for (;;) {
              Message msg = queue.next(); // might block
              if (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 logger
              final Printer logging = me.mLogging;
              if (logging != null) {
                  logging.println(">>>>> Dispatching to " + msg.target + " " +
                          msg.callback + ": " + msg.what);
              }
              // Make sure the observer won't change while processing a transaction.
              final Observer observer = sObserver;
        
              final long traceTag = me.mTraceTag;
              long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;
              long slowDeliveryThresholdMs = me.mSlowDeliveryThresholdMs;
              if (thresholdOverride > 0) {
                  slowDispatchThresholdMs = thresholdOverride;
                  slowDeliveryThresholdMs = thresholdOverride;
              }
              final boolean logSlowDelivery = (slowDeliveryThresholdMs > 0) && (msg.when > 0);
              final boolean logSlowDispatch = (slowDispatchThresholdMs > 0);
        
              final boolean needStartTime = logSlowDelivery || logSlowDispatch;
              final boolean needEndTime = logSlowDispatch;
        
              if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
                  Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
              }
        
              final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0;
              final long dispatchEnd;
              Object token = null;
              if (observer != null) {
                  token = observer.messageDispatchStarting();
              }
              long origWorkSource = ThreadLocalWorkSource.setUid(msg.workSourceUid);
              try {
                  msg.target.dispatchMessage(msg);
                  if (observer != null) {
                      observer.messageDispatched(token, msg);
                  }
                  dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
              } catch (Exception exception) {
                  if (observer != null) {
                      observer.dispatchingThrewException(token, msg, exception);
                  }
                  throw exception;
              } finally {
                  ThreadLocalWorkSource.restore(origWorkSource);
                  if (traceTag != 0) {
                      Trace.traceEnd(traceTag);
                  }
              }
              if (logSlowDelivery) {
                  if (slowDeliveryDetected) {
                      if ((dispatchStart - msg.when) <= 10) {
                          Slog.w(TAG, "Drained");
                          slowDeliveryDetected = false;
                      }
                  } else {
                      if (showSlowLog(slowDeliveryThresholdMs, msg.when, dispatchStart, "delivery",
                              msg)) {
                          // Once we write a slow delivery log, suppress until the queue drains.
                          slowDeliveryDetected = true;
                      }
                  }
              }
              if (logSlowDispatch) {
                  showSlowLog(slowDispatchThresholdMs, dispatchStart, dispatchEnd, "dispatch", 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.recycleUnchecked();
          }
      }
    

    这里我们看到,mLooper()方法里我们取出了当前线程的 looper 对象,然后从 looper 对象开启了一个死循环 不断地从 looper 内的 MessageQueue 中取出 Message,只要有 Message 对象,就会通过 Message 的 target 调用 dispatchMessage 去分发消息,通过代码可以看出 target 就是我们创建的 handler。

    简单说就是一个死循环不停的从 MessageQueue 中取消息,取到消息就通过 Handler 来进行分发,分发之后回收消息进入消息池,以便重复利用。
      
    从消息队列中取消息调用的是 MessageQueue.next() 方法,之前已经分析过。在没有消息的时候可能会阻塞,避免死循环消耗 CPU。
      
    取出消息之后进行分发调用的是 msg.target.dispatchMessage(msg),msg.target 是 Handler 对象,最后再来看看 Handler 是如何分发消息的。
    
      public void dispatchMessage(Message msg) {
          if (msg.callback != null) { // callback 是 Runnable 类型,通过 post 方法发送
              handleCallback(msg);
          } else {
              if (mCallback != null) { // Handler 的 mCallback参数 不为空时,进入此分支
                  if (mCallback.handleMessage(msg)) {
                      return;
                  }
              }
              handleMessage(msg); // Handler 子类实现的  handleMessage 逻辑
          }
      }
        
      private static void handleCallback(Message message) {
          message.callback.run();
      }
    
    • Message 的 callback 属性不为空时,说明消息是通过 postXXX() 发送的,直接执行 Runnable 即可
    • Handler 的 mCallback 属性不为空,说明构造函数中传入了 Callback 实现,调用 mCallback.handleMessage(msg) 来处理消息
    • 以上条件均不满足,只可能是 Handler 子类重写了 handleMessage() 方法。这好像也是我们最常用的一种形式

Message

Message 字段

public int what;  // 消息标识
public int arg1;  // 可携带的 int 值
public int arg2;  // 可携带的 int 值
public Object obj;  // 可携带内容
public long when;  // 超时时间
public Handler target;  // 处理消息的 Handler
public Runnable callback;  // 通过 post() 发送的消息会有此参数
  • obtain()

    Message 有 public 修饰的构造函数,但是一般不建议直接通过构造函数来构建 Message,而是通过 Message.obtain() 来获取消息。

      public static Message obtain() {
          synchronized (sPoolSync) {
              if (sPool != null) {
                  Message m = sPool;
                  sPool = m.next;
                  m.next = null;
                  m.flags = 0; // clear in-use flag
                  sPoolSize--;
                  return m;
              }
          }
          return new Message();
      }
    

    sPool 是消息缓存池,链表结构,其最大容量 MAX_POOL_SIZE 为 50。obtain() 方法会直接从消息池中取消息,循环利用,节约资源。当消息池为空时,再去新建消息。

  • recycleUnchecked()

    Looper.loop() 方法中最后会调用 msg.recycleUnchecked() 方法吗?这个方法会回收已经分发处理的消息,并放入缓存池中。

      void recycleUnchecked() {
          // Mark the message as in use while it remains in the recycled object pool.
          // Clear out all other details.
          flags = FLAG_IN_USE;
          what = 0;
          arg1 = 0;
          arg2 = 0;
          obj = null;
          replyTo = null;
          sendingUid = -1;
          when = 0;
          target = null;
          callback = null;
          data = null;
        
          synchronized (sPoolSync) {
              if (sPoolSize < MAX_POOL_SIZE) {
                  next = sPool;
                  sPool = this;
                  sPoolSize++;
              }
          }
      }
    

总结

  • Android 通过 Looper、Handler 来实现消息循环机制。Android 的消息循环是针对线程的,每个线程都可以有自己的消息队列和消息循环。
  • Android 系统中的 Looper 负责管理线程的消息队列和消息循环。通过 Looper.myLooper() 得到当前线程的 Looper 对象, 通过 Looper.getMainLooper() 得到当前进程的主线程的 Looper 对象。 Handler 也持有 Looper 对象的引用,通过 Looper.loop() 方法让消息队列循环起来。
  • Handler 被用来发送消息,但并不是真正的自己去发送。它持有 MessageQueue 对象的引用,通过 MessageQueue 来将消息入队。
  • Looper 持有 MessageQueue 对象应用,在 loop() 方法中会调用 MessageQueue 的 next() 方法来不停的取消息。
  • loop() 方法中取出来的消息最后还是会调用 Handler 的 dispatchMessage() 方法来进行分发和处理。

补充

内存泄漏

Handler在使用过程中,需要注意的问题之一便是内存泄漏问题。

首先Handler使用是用来进行线程间通信的,所以新开启的线程是会持有Handler引用的, 如果在Activity等中创建Handler,并且是非静态内部类的形式,就有可能造成内存泄漏。

  1. 首先,非静态内部类是会隐式持有外部类的引用,所以当其他线程持有了该Handler,线程没有被销毁,则意味着Activity会一直被Handler持有引用而无法导致回收。
  2. 同时,MessageQueue中如果存在未处理完的Message,Message的target也是对Activity等的持有引用,也会造成内存泄漏。

解决的办法

  1. 使用静态内部类+弱引用的方式:

静态内部类不会持有外部类的的引用,当需要引用外部类相关操作时,可以通过弱引用还获取到外部类相关操作,弱引用是不会造成对象该回收回收不掉的问题。

private Handler sHandler = new TestHandler(this);

static class TestHandler extends Handler {
    private WeakReference<Activity> mActivity;
    TestHandler(Activity activity) {
        mActivity = new WeakReference<>(activity);
    }

    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
        Activity activity = mActivity.get();
        if (activity != null) {
            //TODO:
        }
    }
}
  1. 在外部类对象被销毁时,将MessageQueue中的消息清空。例如,在Activity的onDestroy时将消息清空
    @Override
    protected void onDestroy() {
     handler.removeCallbacksAndMessages(null);
     super.onDestroy();
    }