面试经典题Handler机制回答
Handler机制的问题
相信很多人都遇到过这样的面试题。
那为什么需要Handler呢,你们有反问过自己 || 面试官吗?
看完这篇文章相信你下次去面试就能好好的刷一下面试官的气焰了(装逼),毕竟很多公司本身没有android开发人员,面试题都是网上找的,或者理解不深。
- 为什么要有Handler
- 从源码角度理解该机制
本文为楼主原创,转载请表明出处:http://blog.csdn.net/Suma_sun/article/details/51427312
Handler的由来
首先为什么需要Handler呢? ——因为UI更新只能在UI线程。
那为什么只能在UI线程更新UI呢?——因为Android是单线程模型。
那为什么Android是单线程模型?
那是因为如果任意线程都可以更新UI的话,线程安全问题处理起来会相当麻烦复杂,所以就规定了Android是单线程模型,只允许在UI线程更新UI操作。
Handler机制
Handler机制有几个核心类:Handler、Looper、Message、MessageQueue。
Handler机制是一个典型的生产者消费者模式——多个生产者,一个消费者,该模式是处理线程安全的一个经典模式,如果不了解的请自行查阅相关资料,不懂也没关系,并不影响接下来的内容。
关联Looper
首先我们常用的构造方法
/** * Default constructor associates this handler with the {@link Looper} for the current thread. * * If this thread does not have a looper, this handler won't be able to receive messages * so an exception is thrown. */ public Handler() { this(null, false); }
默认的构造器 new Handler() 会从当前线程获取Looper关联。
如何关联呢?
public Handler(Callback callback) { this(callback, false); }public Handler(Looper looper) { this(looper, null, false); } public Handler(Looper looper, Callback callback) { this(looper, callback, false); }
下面这个构造是所有传入null Looper的归属
//默认不开启private static final boolean FIND_POTENTIAL_LEAKS = false;public Handler(Callback callback, boolean async) { if (FIND_POTENTIAL_LEAKS) { //当子类是匿名类 或者 是成员类 或者 本地类时 //并且不是静态类时进行打印 //获取该类的修饰符 & 静态修饰符常量,&位运算,将值转为二进制进行对位比较,当某一位都为1时该位结果为1,只要某位有一个为0时结果位为0 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()); } //用于警告开发者该类可能存在泄漏 } mLooper = Looper.myLooper(); 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; }
mLooper = Looper.myLooper();//关联Looper关键代码
//Return the Looper object associated with the current thread. Returns null if the calling thread is not associated with a Looper.
意思是返回当前线程的Looper对象,如果为空告知线程关联Looper
所以当我们在Activity中创建Handler没问题,而在子线程中创建会报错的原因就在这里
获取消息
在Looper中有一函数loop();该函数会一直轮循获取消息,直到没有消息返回退出。
//...... 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 Printer logging = me.mLogging; if (logging != null) { logging.println(">>>>> Dispatching to " + msg.target + " " + msg.callback + ": " + msg.what); } msg.target.dispatchMessage(msg); if (logging != null) { logging.println("<<<<< Finished to " + msg.target + " " + msg.callback); } ...... }
在MessageQueue中找到next()方法
Message next() { //...... for(;;){ //...... 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 (false) Log.v("MessageQueue", "Returning message: " + msg); 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; } //...... }
该方法也是一个轮循,并且是带同步块的操作,直到返回Message,或者调用quit(boolean safe)方法 改变mQuitting 使其返回null。
//Looperpublic void quit() { mQueue.quit(false); }
处理消息
获取到Message后会调用其持有的Handler对象dispatchMessage(msg)方法
msg.target.dispatchMessage(msg);
Message中找到如下代码
Handler target; Runnable callback;
Handler
/** * Handle system messages here. */ public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } }
Handler收到消息后,先判断消息内的回调Runnable是否为空//post(Runnable)等方法
,为空就调用Handler内部的Runnable,
public Handler(Callback callback) { this(callback, false); }public Handler(Looper looper) { this(looper, null, false); }
然后调用handleMessage(msg);
public interface Callback { public boolean handleMessage(Message msg); }
上面已经就这源码关键代码梳理了一遍,部分代码并不全面,请各位自行查看源码,这样更加深刻。
更多相关文章
- Android(安卓)Handler解析
- Android退出程序(二)——利用广播机制
- Android-使用HttpURLConnection实现多线程下载
- AsyncTask 完全解析
- Android通知栏-Notification(通知消息)
- Intent 对象在 Android(安卓)开发中的应用
- Android(安卓)异常捕获
- view的绘制机制(一)
- android中对线程池的理解与使用