一、Handler简单应用
为了更直观地分析handler的原理,首先看一个Handler的简单用法,代码如下:
public class MainActivity extends AppCompatActivity {
private static final int MSG_WHAT = 0x001;
private static final String HANDLER_KEY = "handler_key";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new Thread(new Runnable() {
@Override
public void run() {
Message msg = mHandler.obtainMessage();
msg.what = MSG_WHAT;
Bundle bundle = new Bundle();
bundle.putString(HANDLER_KEY, "handler message");
msg.setData(bundle);
mHandler.sendMessage(msg);
}
}).start();
}
Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if (msg.what == MSG_WHAT) {
Log.i("msg content:", msg.toString());
}
}
};
}
代码十分简单,首先新创建一个Handler对象,并重写了Handler的 handleMessage 方法,在 onCreate 函数中启动了一个线程,在线程中调用 mHandler 发送一个消息 msg,然后我们会在刚才重写的 handleMessage 方法中接收并处理 msg。整个消息传递的过程看起来十分简单,清晰明了。
二、Handler原理解析
上面我们看到了Handler使用的一个简单例子,那么Android内部到底是如何实现这种机制的呢,下面将通过分析Handler的源码一步步进行解析。
首先,看一下Handler的构造函数,Handler的构造函数有很多个,一般我们的调用主要会进入下面这个,
public Handler(Callback callback, boolean async) {
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());
}
}
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;
}
这里有两个需要注意的地方,一个是Handler持有Looper对象的引用,那么这个Looper对象的引用指向的是哪呢,我们知道每个线程都有一个Looper,而 Looper.myLooper() 返回的又是当前线程的Looper,当前线程又是哪个呢,因为我们的Hander对象是在主线程,也就是UI线程中创建的,所有Handler持有的正是UI线程的Loopder。而是Hander持有一个消息队列的引用,消息队列对象是从Looper中拿到的,自然也就是UI线程中的消息队列。
好了,下一步来继续分析Handler发消息的过程,上面例子中的 sendMessage(msg) 方法最后会进入下面的函数
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);
}
下面主要是想将msg放入Handler持有的消息队列中,下面进一步看下 enqueueMessage 方法
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
这里在将msg对象放入消息队列之前,先将它的target变量指向当前Handler对象,注意这一点也是使用Handler容易导致内存泄漏的地方。
Handler将msg放入消息队列,此时它的发送工作就算完成了,下面的工作要由Looper接手一下,看一下的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.");
}
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();
//死循环
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);
}
//调用Handler的dispatchMessage函数分发消息
msg.target.dispatchMessage(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();
}
}
loop函数的代码比较多,可以只关注有中文注释的地方,可以看出loop的主要作用是通过一个死循环不断地从消息队列中取出消息,然后通过msg里的target分发消息,这个target前面已经分析过了,就是msg所持有的Handler对象,也就是发送msg的那个Handler,这样处理msg的代码又回到了Handler的代码中。
下面继续看Handler的 dispatchMessage 函数
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
到这里已经可以看到 handleMessage 方法了,不过显然 dispatchMessage 里并没有直接调用 handleMessage,这是因为Handler的使用方法不止上面例子中的一种,例如,也可以通过下面的方式调用Handler
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
}
}, 1000);
这种方式会默认创建一个msg对象,并将msg的callback指向Runnable对象,这就对应 dispatchMessage 的第一个分支 if (msg.callback != null)。
另外,还可以通过如下的方式调用Handler
Handler handler = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
return false;
}
});
这对应 dispatchMessage 的 else 分支里的 if (mCallback != null),这里还要判断Callback里的handleMessage 是返回 true 还是返回 false, 如果返回false还是会继续进入 Handler里的 handleMessage 方法的。至此,Handler的源码已分析完毕。
三、总结
通过以上对Handler源码的分析,其实Handler的调用原理,可以用一句话来描述:Handler对象在创建时会持有当前线程的消息队列,Handler在发送消息时,该消息会持有Handler对象,创建Handler那个线程的Looper对象会不断地从消息队列中取出消息,并通过该消息持有的Handler对象分发消息。
网友评论