Android之Handler机制
来源:互联网 发布:女大十八变知乎 编辑:程序博客网 时间:2024/06/03 10:04
Handler:操作者Message:消息MessageQueue:消息队列Looper:做环的人Loop:环prepare:准备
这些词都是我们在子线程跟UI线程通讯是经常用到的类或者方法,下面分析开发中比较常用的简单的线程间通讯以及它们之间的关系
具体代码如下:
第一种:
public class mThead extends Thread{@Overridepublic void run() {Message msg=Message.obtain();msg.what=0;mHandler.sendMessage(msg);super.run();}}public Handler mHandler=new Handler(){public void handleMessage(Message msg) {if(msg.what==0){Toast.makeText(MainActivity.this, "通讯成功", Toast.LENGTH_SHORT).show();}};};
第二种:
public class hThread extends Thread{@Overridepublic void run() {Looper.prepare();Toast.makeText(MainActivity.this, "通讯成功", Toast.LENGTH_SHORT).show();Looper.loop();super.run();}}
第一种通讯分析:子线程mThead通过handler作为传输纽带,把Toast的信息加入消息队列MessageQueue,就好像是纽带传输货物一样,把子线程mThead作为动力,handler作为纽带,message作为货物,MessageQueue作为货物仓库,Looper对象作为仓管部门,UI线程作为老板,message被handler依靠mThread动力运输到仓库MessageQueue(入队消息到消息队列中的所有挂起的消息)后,仓管员通过Looper.prepare()给UI线程(老板)打电话,提示有货物待处理,UI线程就会要求looper对象循环取出MessageQueue里面的message(消息),直到循环结束,然后UI线程进行处理。
第二种通讯分析:就是Looper.prepare()把Toast信息加入MessageQueue,再通过Looper.loop()循环取出,交给UI线程处理,当MessageQueue队列中没有了message,循环就结束。
经过大体的分析Thread和UI线程通过handler通讯,下面将具体分析这些进程的详细流程
首先看看Handler对象调用的方法
public final boolean sendMessage(Message msg) { return sendMessageDelayed(msg, 0); }public final boolean sendEmptyMessage(int what) { return sendEmptyMessageDelayed(what, 0); } public final boolean sendEmptyMessageDelayed(int what, long delayMillis) { Message msg = Message.obtain(); msg.what = what; return sendMessageDelayed(msg, delayMillis); }public final boolean sendMessageDelayed(Message msg, long delayMillis) { if (delayMillis < 0) { delayMillis = 0; } return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis); }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); } private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { msg.target = this; if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis); }
从上述代码中可以看出,Handler把Message加入MessageQueue队列中经过了sendMessageDelayed→sendMessageAtTime→enqueueMessage方法,重点在于enqueueMessage的方法上,从代码可以看出msg.target = this,把msg的target属性赋值为当前的handler对象,就是把handler发送的信息,加入消息队列中,然后再给Looper.loop()方法取出消息。
下面来看Looper主要代码
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)); } 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 final Printer logging = me.mLogging; if (logging != null) { logging.println(">>>>> Dispatching to " + msg.target + " " + msg.callback + ": " + msg.what); } final long traceTag = me.mTraceTag; if (traceTag != 0) { Trace.traceBegin(traceTag, msg.target.getTraceName(msg)); } try { msg.target.dispatchMessage(msg); } finally { if (traceTag != 0) { Trace.traceEnd(traceTag); } } 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(); } } /** * Return the Looper object associated with the current thread. Returns * null if the calling thread is not associated with a Looper. */ public static @Nullable Looper myLooper() { return sThreadLocal.get(); }
private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread(); }
当Handler发送的信息加入了消息队列,也就是MessageQueue,就需要有人通知UI线程并且从队列中把信息取出来;从上述代码中可以看出,Looper.prepare()方法把方法体加入消息队列,然后loop方法通过循环把MessageQueue里面的消息一个个取出来。
目前对于api分析就那么多,有需要最好自己去研究Handler、Message、Looper、MessageQueue的源码。
希望能帮到大家去更好的理解handler和线程通讯
不足之处,请留言指出,谢谢!
- Android之handler机制
- Android之Handler机制
- Android之Handler机制
- Android之Handler机制
- android 机制之handler机制
- android消息机制 之Handler
- Android之Handler消息机制
- Android之Handler消息机制
- Android之Looper-Handler机制
- Android多线程机制之Handler
- Android之Handler消息机制
- Android消息机制之Handler
- Android消息机制之Handler
- Android09--Android之Handler机制
- Android之Handler消息机制
- Android机制之Handler解析
- Android消息机制之Looper和Handler
- Android学习之Handler通信机制
- 读面试题有感
- leetcode_15. 3Sum-求数组中三个数和为0
- makefile之-Wall
- Hexo 添加多说评论
- 【linux】/etc/inittab文件详解
- Android之Handler机制
- java网络编程____httpclient长连接请求长轮询
- Spring 4.X 版本 json配置记录
- L1和L2的区别和各自的优势
- 学习Python的比较好的网站
- 常见向量范数和矩阵范数
- CentOS多网卡下 应用层无法收到组播的问题解决
- golang 如何重写http 请求处理
- Spring Data JPA Repository