目的:handle的出现主要是为了解决线程间通讯。
举个例子,android是不允许在主线程中访问网络,因为这样会阻塞主线程,影响性能,所以访问网络都是放在子线程中执行,对于网络返回的结果则需要显示在主线程中,handler就是连接主线程和子线程的桥梁。
1.handler基本使用方法
看一下使用方法:
public static final int EMPTY_MSG = 0; @SuppressLint("HandlerLeak") Handler handler = new Handler(){ @Override public void handleMessage(Message msg) { switch (msg.what){ case 0: Toast.makeText(MainActivitys.this, "接受到消息", Toast.LENGTH_SHORT).show(); break; } } }; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); new Thread(new Runnable() { @Override public void run() { handler.sendEmptyMessage(0); } }).start(); }
通过上边代码就完成了子线程向主线程发送消息的功能。
2. handler,Looper,MessageQueue 解释
handler:负责发送和处理消息
Looper:消息循环器,也可以理解为消息泵,主动地获取消息,并交给handler来处理
MessageQueue:消息队列,用来存储消息
3.源码分析
程序的启动是在ActivityThread的main方法中
public static void main(){ Looper.prepare(); //1 Handler handler = new Handler();//2 Looper.loop(); //3 }
Looper.prepare()会初始化当前线程的looper
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)); }
会调用到sThreadLocal.set()方法,ThreadLocal是线程安全的,不同的线程获取到的值是不一样的,下面先分析一下ThreadLocal是如何做到线程安全。
public void set(T value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); }
不同的线程会设置不同的looper,下面看一下ThreadLocalMap是如何存储数据的
ThreadLocalMap(ThreadLocal firstKey, Object firstValue) { table = new Entry[INITIAL_CAPACITY]; int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1); table[i] = new Entry(firstKey, firstValue); }
ThreadLocalMap会创建一个数组,key是通过特殊的算法来创建出来,一个线程中会有一个ThreadLocalMap,这个map中会存多个ThreadLocal和values。
下面看下ThreadLocalMap是如何set一个值的
private void set(ThreadLocal key, Object value) { // We don't use a fast path as with get() because it is at // least as common to use set() to create new entries as // it is to replace existing ones, in which case, a fast // path would fail more often than not. Entry[] tab = table; int len = tab.length; int i = key.threadLocalHashCode & (len-1); for (Entry e = tab[i]; e != null; e = tab[i = nextIndex(i, len)]) { ThreadLocal k = e.get(); if (k == key) { e.value = value; return; } if (k == null) { replaceStaleEntry(key, value, i); return; } } tab[i] = new Entry(key, value); int sz = ++size; if (!cleanSomeSlots(i, sz) && sz >= threshold) rehash(); }
其实是遍历threadLocalMap中的table,如果当前table中存在threadLocal这个key就更新,不存在就新建。ThreadLocal的set方法到此结束。
下面看下Handler handler = new Handler()中执行了哪些操作:
public Handler(Callback callback, boolean async) { mLooper = Looper.myLooper(); mQueue = mLooper.mQueue; }
重要的就是构造函数中这两个方法,在handler中初始化looper和messageQueue。这个就不展开讲了。
下面看一下Looper.loop()这个步骤,我做了一些精简,把无关的代码去掉了。
public static void loop() { final Looper me = myLooper(); final MessageQueue queue = me.mQueue; for (;;) { Message msg = queue.next(); // might block if (msg == null) { // No message indicates that the mes