android异步消息机制,Handler,Looper,MessageQueue的关系

前言:

  参考了鸿洋_大神的这篇文章:http://blog.csdn.net/lmj623565791/article/details/38377229

 (1)在android中线程间的消息通信是通过handler实现的。handler的常见应用:因为在android中对UI操作只能在主线程中操作,而一些耗时的操作又不能在主线程进行,所以会在子线程做一些网络请求等的耗时操作,然后通过handler把子线程的任务切换到主线程中,在主线程中进行UI操作。如下代码:

 private Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        new Thread(new Runnable() {
            @Override
            public void run() {
                Message message = Message.obtain();
                message.what = 1;
                handler.sendMessage(message);
            }
        }).start();

    }

 (2)handler的运行其实需要looper和messageQueue支持,只是当新建Activity已经帮我们新建了looper和messageQueue。如果在子线程使用handler,必须调用Looper.prepare和Looper.loop。如下代码:

    class MyThread implements Runnable{

        private Handler handler;

        @Override
        public void run() {
            Looper.prepare();
            handler = new Handler(){
                @Override
                public void handleMessage(Message msg) {
                    super.handleMessage(msg);
                }
            };
            Looper.loop();
        }
    }

(3)handler的应用流程。首先通过Looper.prepare(),将Looper绑定到当前线程,创建Looper实例时会创建一个MessageQueue。当新建一个Handler实例时会获取到当前的线程的Looper和MessageQUeue。当通过handler.sendMessage(message)方法时会把Message插入到MessageQueue中。最后通过Looper.loop()不停遍历MessageQueue,得到Message,并交给msg.target处理,target就是当前handler(handle赋值给msg.target是在handler.sendMessage(message)中实现的)。target会调用msg.target.dispatchMessage(msg)处理,dispatchMessage最后会调用 handleMessage(msg)处理message。handleMessage也是我们需要重写的方法。下面将下各方法的实现原理。


1.Looper.prepare()


Looper.prepare()的作用是创建一个Looper并绑定到当前线程,同时创建一个MessageQueue。Looper绑定到当前线程通过ThreadLocal实现的。

ThreadLocal的作用:为不同线程互不干扰的存储和提供数据(具体原理可以看下singwhatiwanna大神的这篇文章点击打开链接)。

在代码的78行sThreadLocal.set(new Looper(quitAllowed)),新建了一个Looper实例存储到了ThreadLocal中,并在这之前判定了ThreadLocal之前是否存储了Looper,不为null则抛出异常,这样保证了一个线程只有一个Looper。


51 
52 public final class More ...Looper {
53     private static final String TAG = "Looper";
54 
55     // sThreadLocal.get() will return null unless you've called prepare().
56     static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
57     private static Looper sMainLooper;  // guarded by Looper.class
58 
59     final MessageQueue mQueue;
60     final Thread mThread;
61 
62     private Printer mLogging;
</pre><pre name="code" class="html"></pre><pre name="code" class="html">70     public static void More ...prepare() {
71         prepare(true);
72     }
73 
74     private static void More ...prepare(boolean quitAllowed) {
75         if (sThreadLocal.get() != null) {
76             throw new RuntimeException("Only one Looper may be created per thread");
77         }
78         sThreadLocal.set(new Looper(quitAllowed));
79     }

下面看下Looper的构造方法。在新建Looper会创建一个MessageQueue。一个就实现了一个线程只有一个Looper和MessageQueue。

private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mRun = true;
        mThread = Thread.currentThread();
}

2.新建一个Handler对象。

  Handler的构造方法的第198行mLooper = Looper.myLooper()获取了当前线程的Looper。再看下Looper.myLooper()的实现,其实是获取了LocalThread存储的Looper, return sThreadLocal.get()第161行,就是在代码78行保存的Looper。 
mQueue = mLooper.mQueue(203行)获取了MessageQueu。这样通过新建一个Handler对象,通过ThreadLocal使Handler和Looper,MessageQueue联系到一起。


187
188    public More ...Handler(Callback callback, boolean async) {
189        if (FIND_POTENTIAL_LEAKS) {
190            final Class<? extends Handler> klass = getClass();
191            if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
192                    (klass.getModifiers() & Modifier.STATIC) == 0) {
193                Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
194                    klass.getCanonicalName());
195            }
196        }
197
198        mLooper = Looper.myLooper();
199        if (mLooper == null) {
200            throw new RuntimeException(
201                "Can't create handler inside thread that has not called Looper.prepare()");
202        }
203        mQueue = mLooper.mQueue;
204        mCallback = callback;
205        mAsynchronous = async;
206    }

myLooper方法,通过sThreadLocal.get()获取了保存在ThreadLocal当前线程的Looper.

160    public static Looper More ...myLooper() {
161        return sThreadLocal.get();
162    }

3.handler.sendMessage(message)

先看下代码。不管是sendMessage还是sendEmptyMessage最后都是调用enqueueMessage(626行开始).我们看下enqueueMessage方法实现。queue.enqueueMessage(msg, uptimeMillis)(631行)把message加入到了MessageQueue中。msg.target = this(627行),把当前Handler赋值给了msg.taget。当Looper遍历MessageQueue,取出Message会交给msg.taget处理,也就是交给handler处理了。

 
 
 
 
 
 
505 public final boolean More ...sendMessage(Message msg)
506    {
507        return sendMessageDelayed(msg, 0);
508    }


 
 
516
517    public final boolean More ...sendEmptyMessage(int what)
518    {
519        return sendEmptyMessageDelayed(what, 0);
520    }

 
 
531    public final boolean More ...sendEmptyMessageDelayed(int what, long delayMillis) {
532        Message msg = Message.obtain();
533        msg.what = what;
534        return sendMessageDelayed(msg, delayMillis);
535    }


 
 
592    public boolean More ...sendMessageAtTime(Message msg, long uptimeMillis) {
593        MessageQueue queue = mQueue;
594        if (queue == null) {
595            RuntimeException e = new RuntimeException(
596                    this + " sendMessageAtTime() called with no mQueue");
597            Log.w("Looper", e.getMessage(), e);
598            return false;
599        }
600        return enqueueMessage(queue, msg, uptimeMillis);
601    }


 
626    private boolean More ...enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
627        msg.target = this;
628        if (mAsynchronous) {
629            msg.setAsynchronous(true);
630        }
631        return queue.enqueueMessage(msg, uptimeMillis);
632    }



4.Looper.loop().

当MessageQueue有消息时,会遍历MessageQueue,获取到Message,然后交给Handler处理。MessageQueue没有消息时则处于阻塞状态。

  public static void More ...loop() {
110        final Looper me = myLooper();
111        if (me == null) {
112            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
113        }
114        final MessageQueue queue = me.mQueue;
115
116        // Make sure the identity of this thread is that of the local process,
117        // and keep track of what that identity token actually is.
118        Binder.clearCallingIdentity();
119        final long ident = Binder.clearCallingIdentity();
120
121        for (;;) {
122            Message msg = queue.next(); // might block
123            if (msg == null) {
124                // No message indicates that the message queue is quitting.
125                return;
126            }
127
128            // This must be in a local variable, in case a UI event sets the logger
129            Printer logging = me.mLogging;
130            if (logging != null) {
131                logging.println(">>>>> Dispatching to " + msg.target + " " +
132                        msg.callback + ": " + msg.what);
133            }
134
135            msg.target.dispatchMessage(msg);
136
137            if (logging != null) {
138                logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
139            }
140
141            // Make sure that during the course of dispatching the
142            // identity of the thread wasn't corrupted.
143            final long newIdent = Binder.clearCallingIdentity();
144            if (ident != newIdent) {
145                Log.wtf(TAG, "Thread identity changed from 0x"
146                        + Long.toHexString(ident) + " to 0x"
147                        + Long.toHexString(newIdent) + " while dispatching to "
148                        + msg.target.getClass().getName() + " "
149                        + msg.callback + " what=" + msg.what);
150            }
151
152            msg.recycleUnchecked();
153        }
154    }

在代码110到114行获取了Looper和MessageQueue,如果Looper为空则会抛出异常。

代码121到153无限便利MessageQueue.

代码122行(Message msg = queue.next();)获取到了Message,如果没有则处于阻塞状态。

代码135行(msg.target.dispatchMessage(msg);)msg交给了msg.target处理,target就是在新建Handler实例时赋值给它的当前Handler。这里把msg交给了handler.dispatchMessage(msg)处理,我们看下dispatchMessage的代码。

</pre><pre name="code" class="html">93     public void More ...dispatchMessage(Message msg) {
94         if (msg.callback != null) {
95             handleCallback(msg);
96         } else {
97             if (mCallback != null) {
98                 if (mCallback.handleMessage(msg)) {
99                     return;
100                }
101            }
102            handleMessage(msg);
103        }
104    }


在dispatchMessage方法中如果msg.callback和mCallback为null则交给102行(handleMessage(msg);)处理,handlerMessage就是我们需要重写,去处理返回的消息。
如果msg.callback不为null,看下95行handleCallback(msg),该方法实现739行(message.callback.run()),其实callback就是一个Runnable。我们在handler.post(runnable)设置了callback。


 
     private static void More ...handleCallback(Message message) {
739        message.callback.run();
740    }
741

我们看下post方法。其实在post方法中也是调用了sendMessageDelayed(326行),这个和sendMessage,sendEmptyMessage最后调用的方法是一样的。sendMessageDelayed方法的第一个参数类型是Message.我们看下getPostMessage方法。它的实现其实就是创建了一个空的Message,给Message.callback赋值了Runnable,727行(m.callback = r),而 m.callback就是在dispatchMessage方法中最后消息交给其处理(95行)。所以handler.post(runnable)实现了消息的发送(sendMessage),消息传递过来后的处理(handleMessage(msg);)。发送Message时,只是携带了Runnable的一个空的Message,最后在message.callback.run()(739行)处理消息。所以我们要重写run方法处理消息。

324    public final boolean More ...post(Runnable r)
325    {
326       return  sendMessageDelayed(getPostMessage(r), 0);
327    }


725    private static Message More ...getPostMessage(Runnable r) {
726        Message m = Message.obtain();
727        m.callback = r;
728        return m;
729    }
730


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值