Handler机制是面试中的常客了,今天和你们一块儿经过源码层面来解析一下。
@[toc]java
Handler机制涉及到几个类: MessageQueue, Looper, Message, ActivityThread。面试
AppCompatActivity.java-> FragmentActivity.java->SupportActivity.java->Activity.javaapp
在Activity中默认有一个ActivityThread这是一个main thread,其中final Looper mLooper = Looper.myLooper();实例化了一个looper对象。
在ActivityThread.java中的main方法中,有以下代码ide
public static void main(String[] args) { ...省略其余代码 Looper.prepareMainLooper(); ...省略其余代码 Looper.loop(); }
Looper.java public static void prepareMainLooper() { prepare(false); synchronized (Looper.class) { if (sMainLooper != null) { throw new IllegalStateException("The main Looper has already been prepared."); } sMainLooper = myLooper(); } } 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)); } // Looper构造函数中初始了消息队列MessageQueue对象 private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread(); }
建立looper 对象以前,会判断 sThreaLocal 中是否已经绑定过 Looper 对象,若是是则抛出异常,确保一个线程中Looper.prepare()只调用一次。
若是在MainActivity中调用,以下代码,会报错。
函数
经过上述代码能够得知,Activity中默认开始了loop()循环,用于获取handler发送的消息。oop
public class MainActivity extends AppCompatActivity implements View.OnClickListener { private final String TAG = "MainActivity"; public final int MSG_DOWN_FAIL = 1; public final int MSG_DOWN_SUCCESS = 2; public final int MSG_DOWN_START = 3; @BindView(R.id.btn_start_thread) Button btnStart; @BindView(R.id.tv_status) TextView tvShow; private Handler handler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case MSG_DOWN_START: tvShow.setText("down start"); break; case MSG_DOWN_SUCCESS: tvShow.setText("down success"); break; case MSG_DOWN_FAIL: tvShow.setText("down fail"); break; default: break; } } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ButterKnife.bind(this); btnStart.setOnClickListener(this); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.btn_start_thread: new MyThread().start(); break; default: break; } } class MyThread extends Thread { @Override public void run() { handler.sendEmptyMessage(MSG_DOWN_START); try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } Message msg = Message.obtain(); msg.what = MSG_DOWN_SUCCESS; handler.sendMessage(msg); } } }
public final boolean sendMessage(Message msg) { return sendMessageDelayed(msg, 0); }
sendMessage调用了sendMessageDelayed->sendMessageAtTime->enqueueMessage, 最终调用了MessageQueue的enqueueMessage的方法, 并将本身设置为message的targetpost
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { msg.target = this; if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis); }
接下来就到了消息队列MessageQueue中了,来看一下ui
其实这里就是Looper.loop()方法从消息队列中不断循环取消息了。
不断调用MessageQueue的next()方法取消息,若是message不为null, 则调用handler的dispatchMessage分发消息。
这个handleMessage方法就是在建立Handler中覆盖的方法。this
至此 Handler 的发送消息和消息处理流程已经介绍完毕。spa
Android的Ui线程,开启了一个死循环,可是并无阻塞主线程是为何呢?
在MessageQueue的next方法中有这样一行代码
private native void nativePollOnce(long ptr, int timeoutMillis); /*non-static for callbacks*/
nativePollOnce 方法是一个 native 方法,当调用此 native 方法时,主线程会释放 CPU 资源进入休眠状态,直到下条消息到达或者有事务发生,经过往 pipe 管道写端写入数据来唤醒主线程工做,这里采用的 epoll 机制。
messageQueue的enqueueMessage是按照消息的when时间有序加入到队列的,取的时候也是按照时间进行取的
能够看到若是当前时间小于msg设置的时间,会计算一个timeout,在timeout到了以后,才会将UI线程唤醒,交由CPU执行。
1.APP启动建立主线程的时候会经过ActivityThread执行Looper.prepare(),建立一个looper 对象,在私有的构造方法中又建立了 MessageQueue 做为此 Looper 对象的成员变量,Looper 对象经过 ThreadLocal 绑定 MainThread 中。2.在建立Handler对象的时候,经过构造函数获取ThreadLocal 绑定的looper对象,并经过looper获取消息队列MessageQueue做为成员变量3.子线程发送消息时,将msg的target设置为handler自身,以后调用成员MessageQueue的enqueueMessage将消息按照msg.when时间排序插入到消息队列4.主线程经过Looper.loop()开启不阻塞UI线程的死循环,经过绑定的looper对象获取MessageQueue,调用next()方法不断获取msg, 并经过(handler)msg.target.dispatchMessage发送至咱们建立的handler时覆盖的handleMessage()方法