首页 / 操作系统 / Linux / Handler的相关知识和应用
最近我在网路上查了很多关于handler的知识,但是感觉总是觉得有很多问题??1.为什么要使用handler?2.handler是异步的,创建一个handler实例是创建一个新的线程吗??(NO,没有创建新的线程,但是为什么没有阻塞主线程?这是有系统管理Looper的)3.在同一线程中,handler1发送消息,handler1能收到消息,handler2能收到吗?4.在子线程中,运用主线程中定义的handler,sendMessage,主线程中得handler能收到吗?5.在子线程中创建一个handler实例,并发送消息,这样可以吗???6.HandlerThread是什么,什么时候使用??7.Message,Looper,Handler,MessageQueue等地关系如何???8.sendMessage和post的区别是什么??是否共用一个消息队列messageQueue??9.handler是再主线程内吗?(不一定,一般是的,但是如果在handler的构造函数中传入子线程的Looper,则就会在该线程中)10.子线程中构造的的handler可以传入主线程的Looper,就是操控主线程的消息队列??(可以)带着问题去学习handler,我想应该会很有意思的。下面就是来解决这些问题的,(*^__^*) 嘻嘻……先介绍下handler的基本知识HandlerHandler在Android里负责发送和处理消息。它的主要用途:
1)按计划发送消息或执行某个Runnanble(使用POST方法),类似定时器;
2)从其他线程中发送来的消息放入消息队列中,避免线程冲突(常见于更新UI线程);
默认情况下,Handler接受的是当前线程下的消息循环实例(使用Handler(Looper looper)、Handler(Looper looper, Handler.Callback callback)可以指定线程),同时一个消息队列可以被当前线程中的多个对象进行分发、处理(在UI线程中,系统已经有一个Activity来处理了,你可以再起若干个Handler来处理)。在实例化Handler的时候,Looper可以是任意线程的,只要有Handler的指针,任何线程也都可以sendMessage。Handler对于Message的处理不是并发的。一个Looper 只有处理完一条Message才会读取下一条,所以消息的处理是阻塞形式的(handleMessage()方法里不应该有耗时操作,可以将耗时操作放在其他线程执行,操作完后发送Message(通过sendMessges方法),然后由handleMessage()更新UI)。
LooperLooper类用来创建消息队列. 每个线程最多只能有一个消息队列, android中UI线程默认具有消息队列, 但非UI线程在默认情况下是不具备消息队列的. 如果需要在非UI线程中开启消息队列, 需要调用Looper.prepare()方法, 在该方法的执行过程中会创建一个Looper对象, 而Looper的构造函数中会创建一个MessageQueue instance(Looper的构造函数是私有的, 在Looper类之外无法创建其对象). 此后再为该线程绑定一个Handler instance, 然后调用Looper.loop()方法, 就可以不断的从消息队列中取出消息和处理消息了. Looper.myLoop()方法可以得到线程的Looper对象, 如果为null, 说明此时该线程尚未开启消息队列.
创建一个 Looper 对象时,会同时创建一个 MessageQueue 对象(一个looper对应一个MessageQueue)。除了主线程有默认的 Looper ,其他线程默认是没有 MessageQueue 对象的,所以,不能接受 Message 。如需要接受,自己定义 一个 Looper 对象 ( 通过 prepare 函数 ), 这样该线程就有了自己的 Looper 对象和 MessageQueue 数据结构了。
Looper 从 MessageQueue 中取出 Message 然后,交由 Handler 的 handleMessage 进行处理。处理完成后,调用 Message.recycle() 将其放入 Message Pool 中。
Message
Message :消息对象, Message Queue 中的存放的对象。一个 Message Queue 中包含多个 Message 。 Message 实例对象的取得,通常使用 Message 类里的静态方法 obtain(), 该方法有多个重载版本可供选择;它的创建并不一定是直接创建一个新的实例,而是先从 Message Pool( 消息池 ) 中看有没有可用的 Message 实例,存在则直接取出返回这个实例。如果 Message Pool 中没有可用的 Message 实例,则才用给定的参数创建一个 Message 对象。调用 removeMessages() 时,将 Message 从 Message Queue 中删除,同时放入到 Message Pool 中。除了上面这种方式,也可以通过 Handler 对象的 obtainMessage() 获取 一个 Message 实例。
Message类用于表示消息. Message对象可以通过arg1, arg2, obj字段和setData()携带数据, 此外还具有很多字段.when字段决定Message应该何时出对处理,;target字段用来表示将由哪个Handler对象处理这个消息;next字段表示在消息队列中排在这个Message之后的下一个Message;callback字段如果不为null表示这个Message包装了一个runnable对象;what字段表示code, 即这个消息具体是什么类型的消息. 每个what都在其handler的namespace中, 我们只需要确保将由同一个handler处理的消息的what属性不重复就可以.
MessageQueue
MessageQueue类用于表示消息队列. 队列中的每一个Message都有一个when字段, 这个字段用来决定Message应该何时出对处理. 消息队列中的每一个Message根据when字段的大小由小到大排列, 排在最前面的消息会首先得到处理, 因此可以说消息队列并不是一个严格的先进先出的队列。 主线程创建时,会创建一个默认的 Looper 对象,而 Looper 对象的创建,将自动创建一个 Message Queue 。其他非主线程,不会自动创建 Looper ,要需要的时候,通过调用 prepare 函数来实现。将消息压入消息队列:Message对象的target字段关联了哪个线程的消息队列, 这个消息就会被压入哪个线程的消息队列中.
a 调用Handler类中以send开头的方法可以将Message对象压入消息队列中,;调用Handler类中以post开头的方法可以将一个runnable对象包装在一个Message对象中, 然后再压入消息队列, 此时入队的Message其callback字段不为null, 值就是这个runnable对象. 调用Handler对象的这些方法入队的Message, 其target属性会被赋值为这个handler对象.
b. 调用Message对象的sendToTarget()方法可以将其本身压入与其target字段(即handler对象)所关联的消息队列中. 从消息队列中取出消息并处理消息: 所有在消息队列中的消息, 都具有target字段. 消息是在target所关联的线程上被取出和处理的.
1. 如果取出的Message对象的callback字段不为null, 那么就调用callback字段的run()方法(callback字段的类型是runnable). 注意此时并不开启一个新的线程运行run()方法, 而是直接在handler对象(即Message的target字段)所关联的线程上运行.
2. 如果取出的Message对象的callback字段为null, 且Handler对象中的callback字段也为null, 那么这个消息将由Handler对象的handleMessage(msg)方法处理. 注意Message对象的callback字段是Runnable类型的而Handler对象的callback字段是Callback类型的, Handler对象的callback字段是在创建Handler instance的时候指定的, 如果没有指定则这个字段为null, 详见Handler类的四个构造方法.
3. 如果取出的Message对象的callback字段为null, 且Handler对象中的callback字段不为null, 那么这个消息将由Handler对象中的callback字段的handleMessage方法处理.