Android个人笔记之Android的消息机制

概述

Handler在开发中最常用的就是拿来更新UI了。Handler的运行需要MessageQueue和Looper的支撑。Handler创建的时候会采用当前线程的Looper构造消息循环系统。但线程是默认没有Looper的,需要我们手动创建。除非是主线程,也就是UI线程,它就是ActivityThread。ActivityThread被建立的时候系统就会初始化Looper,所以主线程可以默认使用Handler。Handler创建完毕后,通过Handler的post方法将一个Runnable对象投递到Looper中处理,或者用handler的send方法发送消息,其实post方法最终也是通过send方法调用。

ThreadLocal

ThreadLocal是一个线程内部的数据存储类,通过它可以在指定线程存储数据,所以也只能在指定线程中获取相、应的数据,其他线程则没有办法。平常用到ThreadLocal的地方不多,但有时也挺好用。如果某些数据是以线程为作用域并且不同线程有不同数据副本时,就可以使用ThreaLocal。比如Looper。不同线程有不同的Looper,通过ThreaLocal就可以轻松实现Looper在不同线程中的存取。
我们演示一下ThreadLocal的用法。

private ThreadLocal mBooleanThreadLocal = new ThreadLocal();

接着在主线程,子线程1,子线程2中分别设置和获取它的值。

mBooleanThreadLocal.set(true);
Log.d("TAG","(Thread main)mBooleanThreadLocal ="+mBooleanThreadLocal.get());

new Thread(){
@override
public void run(){
mBooleanThreadLocal.set(false);
Log.d("TAG","(Thread1)mBooleanThreadLocal ="+mBooleanThreadLocal.get());
  }
}.start();

new Thread(){
@override
public void run(){
mBooleanThreadLocal.set(false);
Log.d("TAG","(Thread2)mBooleanThreadLocal ="+mBooleanThreadLocal.get());
  }
}.start();

上面代码输出为

(Thread main)mBooleanThreadLocal =true;
(Thread1)mBooleanThreadLocal =false;
(Thread2)mBooleanThreadLocal =null;

看完你就知道ThreadLocal的神奇之处。同一个ThreadLocal对象得到的值却不同。其实是因为不同线程调用ThreadLocal的get方法,ThreadLocal内部会从各自线程取出一个数组,再从数组中根据当前ThreadLocal的索引查找对应的value值。显然不同线程的数组是不同的。所以ThreadLocal在不同线程中维护一套数据的副本是互不干扰的。

MessageQueue

MessageQueue主要包括两个操作,插入和读取,对应的方法为enqueueMessage和next。enqueueMessage的作用就是往消息队列中插入一条消息。next的作用是取出一则消息读取,并从消息队列中移除。MessageQueue虽然叫做消息队列,实际上却是用单链表的数据结构,因为执行插入和删除效率比较高。

Looper

Looper创建时MessageQueue会跟着创建。并把当前线程的对象保存起来。
在线程中使用Looper的方式如下,注意这里的Handler并不能更新UI。

new Thread(){
@override
public void run(){
Looper.prepare();//创建Looper对象
Handler handler = new Handler();
Looper.loop();//Looper开始工作
  }
}.start();

Looper还提供了退出的方法,quit和quitSafely。调用quit方法会直接退出Looper,而quitSafely只是设定一个退出标记,然后等消息队列中的已有消息全部处理完毕后才退出。Looper退出后,Handler发送的消息会失败。如果在子线程中手动创建Looper,那么所有事情完毕后应调用quit方法终止消息循环。而如果退出Looper后,线程也就被终止了。
Looper.loop()是一个死循环,只有MessageQueue的next方法返回了null才能跳出循环。当Looper的quit方法调用时Looper会调用MeassageQueue的quit方法来通知消息队列退出,此时next方法就会返回null。

Handler的工作原理

先看一下发送消息过程的源码

public final boolean sendMessage(Message msg){
    return sendMessageDelayed(msg, 0);
}
public final boolean sendMessageDelayed(Message msg, long delayMillis){
    if (delayMillis < 0) {
        delayMillis = 0;
    } 
   return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}

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

可以发现,Handler发送消息的过程只是向消息过程中插入一则消息。 MessageQueue的next方法会返回这条消息给Looper,Looper收到后开始处理,最终由Looper交给Handler处理。,这时Handler的dispatchMessage方法被调用。

public void dispatchMessage(Message msg) { 
  if (msg.callback != null) {        
    handleCallback(msg);    
  } else {  
    if (mCallback != null) {            
      if (mCallback.handleMessage(msg)) {                
        return;            
      }        
    }
    //处理sendMessage();方法发送的消息        
    handleMessage(msg);    
  }
}

看上面的代码,Message的callback是一个Runnable对象,就是post方法传递过来的Runnable对象。handleCallback的方法很简单,就是执行run方法。

private static void handleCallback(Message message) {
 message.callback.run();
}

Callback是一个接口。定义为

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

Callback的意义在于可以创建Handler的实例而不用派生Handler的子类。使用方式如下

Handler handler= new Hanlder(Callback);

平常我们一般都是创建Handler的子类并重写handleMessage方法。Callback为我们提供了另一种方式。

我们借助一张图片来理解一下Hanlder消息处理的流程,相信不难理解。

Android个人笔记之Android的消息机制_第1张图片
Handler消息处理流程

以上总结大部分来自《Android开发艺术探索》,想要理解更仔细请翻阅原书。

你可能感兴趣的:(Android个人笔记之Android的消息机制)