Handler机制源码分析(异步一)
来源:互联网 发布:淘宝 作弊 编辑:程序博客网 时间:2024/05/23 22:54
一.场景
Handler 机制是Android异步消息的核心(线程间通信), 其实Handler不局限于子线程与主线程(UI线程) ,我们完全可以创建一个子线程,然后初始化Looper,Handler,我们可以通过Handler在其他线程(包括主线程)往该子线程发送消息。例如系统帮我们封装好的--> HandlerThread (一个封装好Looper,MessageQueueu的线程(不死线程)),发送消息给子线程有什么好处呢, 这里拿HandlerThread说明,现在有个场景, 我们都知道UI线程不能做耗时的操作, 会影响程序的性能,用户体验,所以耗时(IO,网络,数据库操作)操作全部往子线程堆。怎么解决呢, 我们可以创建一个子线程HandlerThread, 拿到该线程的Looper--HandlerThread.getLooper(),然后可以new Handler(Looper).post(Runnable r)往该线程发送消息, 然后就会在该子线程执行消息;
二. 重要的概念(Handler , Looper,MessageQueue,Message)
Handler 看看官方是怎么说的吧 A Handler allows you to send and process Message
and Runnable objects associated with a thread's MessageQueue ,简单说Handler主要的作用就是往MessageQueue插入一个消息
Looper --Looper作用是从MessageQueue读取Message,然后交给Handler处理消息,另外Looper还可以保证线程不死
MessageQueue 消息队列, 链表插入和删除方便, 主要用于存放消息(Message)
Message 消息(消息会包装发送Message的Handler,详细见下面 一一源码验证)
三.源码解析(UI线程应用Handler机制)
<span style="color:#3333ff;"></span>private static final TaskHandler TASK_HANDLER = new TaskHandler();public void doClick(View v) {new Thread(new Runnable() {@Overridepublic void run() {try {Thread.sleep(3000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}Message message = Message.obtain();message.arg1 = ++i;TASK_HANDLER.sendMessage(message);}}).start();}static final class TaskHandler extends Handler {@Overridepublic void handleMessage(Message msg) {Log.i("Info", "message:"+msg.arg1);}}
上面代码很简单, 估计大家都会, 在子线程中睡三秒, 然后往UI线程发送一个消息。很简单就完成了一个子线程和UI线程的通信,并且没有任务问题, 其实,Android在背后为我们做了很多封装和处理了,才可以往UI线程发送消息, 不信见如下:
new Thread(new Runnable() {@Overridepublic void run() {handler = new Handler();handler.sendEmptyMessage(0x33);}}).start();}
在子线程初始化一个Handler,然后发送一个消息。结果:
07-10 15:12:53.251: E/AndroidRuntime(5296): FATAL EXCEPTION: Thread-158
07-10 15:12:53.251: E/AndroidRuntime(5296): java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
07-10 15:12:53.251: E/AndroidRuntime(5296): at android.os.Handler.<init>(Handler.java:121)
07-10 15:12:53.251: E/AndroidRuntime(5296): at com.example.just_intentservice.MainActivity$1.run(MainActivity.java:25)
07-10 15:12:53.251: E/AndroidRuntime(5296): at java.lang.Thread.run(Thread.java:856)
抛出异常了,大概意思是说没有,不能在没有初始化Looper的线程去创建Handler;
点进Handler源码查看下,
public Handler() { 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 = null; }先会到当前线程查找Looper ,如果没有Looper就会抛出上面的异常。所以不能在没有初始化Looper的线程初始化Handler,UI线程之所以可以初始化Handler,我们见以下,Android UI线程是如何初始化Looper吧...
Java应用程序入口都是从mian函数, Android也不例外,只不过被SDK用hide标识着,我们无法查看,看下Android,UI线程是如何玩转Handler机制的,在ActivityThread里面main函数代码如下
public static void main(String[] args) { //******省略若干代码****// Looper.prepareMainLooper();//初始一个Looper Looper.loop();//开始无限循环读取消息 throw new RuntimeException("Main thread loop unexpectedly exited"); }我们代码追踪看Android是如何初始换Looper,在Looper类里面
public static void prepareMainLooper() {//初始化MainLooper也是UI线程的Looper prepare(); setMainLooper(myLooper()); }
public static void prepare() { if (sThreadLocal.get() != null) { throw new RuntimeException("Only one Looper may be created per thread"); } sThreadLocal.set(new Looper()); }
private Looper() { mQueue = new MessageQueue();//初始化一个MessageQueue mThread = Thread.currentThread(); }
先判断下当前线程是否存在Looper,存在抛出异常, 也就是说一个线程自能有一个Looper, 如果没有,则new出一个Looer(在构造方法里面初始化了一个对应的MessageQueue), 然后通过sThreadLocal保存起来, ThreadLocal用于线程保存对象 。然后来看下
setMainLooper(myLooper());
public static Looper myLooper() { return sThreadLocal.get(); }
private synchronized static void setMainLooper(Looper looper) { mMainLooper = looper; }可以看出myLooper就是从当前线程中拿出Looper,然后返回,setMainLooper(),就更简单了,其实就是保存个全局looper。
就这样UI线程就吧Looper初始化完成了,所以Handler可以正常的在主线程初始化;
下面我们来走一把完整的Handler机制通信流程
handler.sendEmptyMessage(0x33); <span style="font-family: Consolas, 'Liberation Mono', Menlo, Monaco, Courier, monospace;">----子线程</span>
public final boolean sendEmptyMessage(int what) { return sendEmptyMessageDelayed(what, 0);// 包装下时间调用两个参数<span style="font-family: Consolas, 'Liberation Mono', Menlo, Monaco, Courier, monospace;">sendEmptyMessageDelayed方法</span> }
public final boolean sendEmptyMessageDelayed(int what, long delayMillis) { Message msg = Message.obtain();//获取一个Message msg.what = what; return sendMessageDelayed(msg, delayMillis); }
public final boolean sendMessageDelayed(Message msg, long delayMillis) { if (delayMillis < 0) { delayMillis = 0;//如果时间小于0则赋值为0 } return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis); }
public boolean sendMessageAtTime(Message msg, long uptimeMillis) { boolean sent = false; MessageQueue queue = mQueue; if (queue != null) {//对消息队列判空 msg.target = this;//this表示当前handler sent = queue.enqueueMessage(msg, uptimeMillis);//进入队列 } else { RuntimeException e = new RuntimeException( this + " sendMessageAtTime() called with no mQueue"); Log.w("Looper", e.getMessage(), e); } return sent; }子线程的handler发送一个简单的空消息到UI线程, 要经过不断的包装, 可以看出,最后都是包装Message然后进入队列(MessageQueue)其实post(Runnable r)最后也是经过包装成Message对象,发送到队列, 这里就不做说明了, 详细见源码。 我们知道Looper在UI线程初始化完成就开始无限死循环读取MessageQueue里面消息,我们看Looper是如何读取和处理消息的:
public static void loop() { Looper me = myLooper();//获取当前线程的Looper if (me == null) { throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); } MessageQueue queue = me.mQueue; //获取Looper里面的消息队列 while (true) { //死循环读取 Message msg = queue.next(); // might block 从队列里面拿到消息 if (msg != null) { if (msg.target == null) { // No target is a magic identifier for the quit message. return; } //省略一些代码 msg.target.dispatchMessage(msg);//从message中拿到handler,然后调用<span style="font-family: Consolas, 'Liberation Mono', Menlo, Monaco, Courier, monospace;">dispatchMessage</span> msg.recycle();//最终销毁消息 } } }Handler类里面的dispatchMessage如下:
public void dispatchMessage(Message msg) { if (msg.callback != null) {//callback其实是一个Runnable对象, 一般post(Runnable r)是执行 handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg);//回调handlerMessage函数--一般该方法由我们继承去实现的 } }
private final void handleCallback(Message message) { message.callback.run();//执行run方法体 }说明下, 子线程handler.sendEmptyMessage()当Message到达MessageQueue,这里就是子线程切换到UI线程了, 因为MessageQueue跑在UI线程,上面代码可以看出,Looper会不断的在MessageQueue里面读取消息,然后读到的message为空的化return掉, 其实里面还有一些唤醒机制(保证UI线程的不阻塞,当消息过来了才唤醒,这里不细说)如果message不为空,则从message中取出handler,然后调用handler的dispathMessage(Message message)方法来方法消息, 如果消息为post(Runnable r)则走handlerCallback,否则走handleMessage(msg),整个消息通信结束。
通过源码分析, 我们完全可以创建一个不死子线程,然后在主线程中往子线程发送消息:
private Handler handler;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);new Thread(new Runnable() {@Overridepublic void run() {Looper.prepare();handler = new Handler(Looper.myLooper()) {@Overridepublic void handleMessage(Message msg) {if (msg.what == 0x88) {Log.i("Info", "i am sub");}}};Looper.loop();}}).start();}
public void doClick(View v) {handler.sendEmptyMessage(0x88);}
最后总结:Handler往MessageQueue插入Message,Looper往messageQueue里面读取message,最后都是交给Handler分发处理。
- Handler机制源码分析(异步一)
- Looper、Message、MessageQueue、Handler异步消息处理机制源码分析
- Android异步消息处理机制详解及源码分析 Handler
- Handler异步消息处理机制的源码分析
- 异步消息处理机制之Handler源码分析篇
- Handler机制.源码分析
- Handler 机制 源码分析
- 源码分析Handler机制
- Android从源码分析一:Looper,Handler消息机制
- android源码分析系列(一):Handler机制
- Handler消息机制源码分析
- Handler 机制-源码分析
- handler机制的源码分析
- handler机制原理源码分析
- Android Handler机制源码分析
- handler机制 源码分析 梳理
- 异步消息处理机制Handler源码解析
- 分析Handler异步消息机制关键步骤
- Word Ladder
- 国外机器学习牛人 慢慢总结慢慢写
- 远程通信的几种选择(RPC,Webservice,RMI,JMS的区别)
- 感知器-----preceptron
- java Web表示层技术
- Handler机制源码分析(异步一)
- python---之jinjia2
- 来!我们来玩一下陀螺仪和加速度计
- POJ 1654 Area
- java Web表示层技术
- SQL SERVER 2012实现数据的完整性
- Excel表单的读取与处理 PHPExcel与Apache POI
- Use KLEE to Test GNU Coreutils
- 从计算机视觉角度深入解读了AR