您的位置:首页 > 移动开发 > Android开发

Android多线程Handler的使用,基于源代码理解。

2014-03-29 00:50 239 查看
第一次接触Handler的时候一头雾水,当时学到了一半就没有再去接触了,这几天又潜下心来细细的研究了一下,根据Mars的视频和自己的理解。在理解Handler的同时,我们也需要理解其它2个对象。分别是:Looper、Message。
Looper,顾名思义,就是一个循环器,是Handler多线程中重要一环,他的作用主要有以下几点:
1、产生MessageQueue对象对象。在实例化Looper对象的时候,会同时实例化一个MessageQueue对象。
2、取出Message对象,并把取出的Message对象交给先前与Looper相关联的Handler对象。
Message,即消息。这就是我们Handler花九牛二虎之力需要“搬迁”到其它线程的对象。细细看看Android源代码,发现其实他的作用主要也有两点:
1、存放需要传输的数据,如使用Message的obj属性等。
2、关联使用了sendMessage方法的对象。[目的是为了在主线程中和使用handMessage方法的Handler一致]
以上都是我个人的理解,可能有办法有误,小伙伴们可以自己去看源码。SORRY...--.--
基于上面的理解,我们来梳理一般要如何使用Handler来处理多线程。总共方法有三步:
1、初始化Looper。(这一步会产生MessageQueue对象)
2、实例化Handler。(这里要记住在哪个线程new 的Handler,Looper就在哪个线程运行)
3、启动Looper,即使Looper开始循环。
下面,我们基于Android源码来理解这三条。在这之前,大家要知道一点,在主线程中系统已经预设了一个Looper,所以主线程向其它线程发送消息时无需启动Looper,直接实例化Handler对象即可。

可以发现,其实实际方法就是三步。
第一步:Looper.prepare();

public static void prepare() {
prepare(true);
}
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姑且可以理解为把new Looper(quitAllowed)存入当前线程。我们再来看看new Looper(quitAllowed)做了什么:

private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);//实例化一个消息队列对象
mRun = true;
mThread = Thread.currentThread();
}

   总结第一步就是我们开始说的,实例化一个Looper和一个消息队列(MessageQueue)对象。

第二步:new Handler();

public Handler() {
this(null, false);
}
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();//myLooper方法就是从当前线程中取出Looper对象(在Looper.prepare()中存进去的),并把其关联到Handler类中的Looper
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;//把开始初始化的消息队列关联到Hander类中的队列
mCallback = callback;
mAsynchronous = async;
}


9c1c
 这一步不再赘述,上面代码已经注释过了。总结以来就是使Handler与Looper和MessageQueue(消息队列)相关联,并且一一对应。
第三步:Looper.loop();

public static void loop() {
final Looper me = myLooper();//从当前线程中取出Looper对象
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;

...

for (;;) {  //死循环。不断从消息队列中取出Message对象,为空则阻塞。
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);//追究源码可以发现,其实就是回调handleMessage方法。
//msg.target就是一个Handler
if (logging != null) { logging.println("<<<<< Finished to " + msg.target + " " + msg.callback); } .... } msg.recycle(); } }

Handler target; //Message类的成员
public void dispatchMessage(Message msg) { //Handler类
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);//回调
}
}

      第三步总结起来就是使Looper循环,取出Message对象,并使用这个对象,来产生回调。即我们重写的handMessage方法。

   第一次写博文,格式就调了1个小时- -请大家海涵。^_^     

==========================================================================================================================================================

更新……我还想解释一下,为什么Handler把消息放到MessageQueue中,然后Looper.loop()取出的时候恰好是我们放进去的Handler。

Message msg = Handler.obtainMessage();


这个obtainMessage()其实是把操作它的Handler放到了Message的属性里的。请看源码:

public final Message obtainMessage()
{
return Message.obtain(this);
}
再追踪Message的obtain方法:

public static Message obtain(Handler h) {
Message m = obtain();
m.target = h; //上面已经说过了,这个m.target就是Hanler,这一步就恰好把Hanlder存入了Message中。

return m;
}
至于取出,大家可以看上面,在Looper对象中loop方法中
msg.target.dispatchMessage(msg);//这个msg.target不就是开始存进来Handler吗?
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息