Handler机制
来源:互联网 发布:商桥2016软件下载 编辑:程序博客网 时间:2024/06/06 07:28
- Looper: 一个线程可以产生一个Looper对象,由它来管理此线程里的MessageQueue(消息队列)。
- Handler: 你可以构造Handler对象来与Looper沟通,以便push新消息到MessageQueue里;或者接收Looper从Message Queue取出)所送来的消息。
- Message Queue(消息队列):用来存放线程放入的消息。
- 线程:UIthread 通常就是main thread,而Android启动程序时会替它建立一个MessageQueue。
小结:handler机制即,我们构造一个Handler对象与线程产生的Looper对象进行沟通,根据Looper生成并管理下MessageQueue中的Message分析所得参数,将message送到对应的handler进行处理。
Handler对象、Looper对象、Message、MessageQueue为机制中的四主体
1、handler机制消息流程
1.1 Handler创建消息
每一个消息都需要被指定的Handler处理,通过Handler创建消息便可以完成此功能。Android消息机制中引入了消息池。Handler创建消息时首先查询消息池中是否有消息存在,如果有直接从消息池中取得,如果没有则重新初始化一个消息实例。
使用消息池的好处是:消息不被使用时,并不作为垃圾回收,而是放入消息池,可供下次Handler创建消息时使用。消息池提高了消息对象的复用,减少系统垃圾回收的次数。消息的创建流程如图所示。
1.2 Handler发送消息
UI主线程初始化第一个Handler时会通过ThreadLocal创建一个Looper,该Looper与UI主线程一一对应。使用ThreadLocal的目的是保证每一个线程只创建唯一一个Looper。之后其他Handler初始化的时候直接获取第一个Handler创建的Looper。Looper初始化的时候会创建一个消息队列MessageQueue。至此,主线程、消息循环、消息队列之间的关系是1:1:1。
Handler、Looper、MessageQueue的初始化流程如图所示:
Hander持有对UI主线程消息队列MessageQueue和消息循环Looper的引用,子线程可以通过Handler将消息发送到UI线程的消息队列MessageQueue中。
1.3 Handler处理消息
UI主线程通过Looper循环查询消息队列UI_MQ,当发现有消息存在时会将消息从消息队列中取出。首先分析消息,通过消息的参数判断该消息对应的Handler,然后将消息分发到指定的Handler进行处理。
子线程通过Handler、Looper与UI主线程通信的流程如图所示。
如果是使用Thread的run()方法,run()结束之后没有返回值。所以必须要自己建立通信机制。但是,其实使用Handler+Thread机制其实完全可以替代AsynTask的这种调用机制。只要将Handler对象传给Thread,就可以进行方便的异步处理。且这种MVC模式结构更加明显,方便管理。所以我觉得,使用asynTask还是Handler+Thread结构,个人喜好吧。但是有一点可以明显能感觉到得是,Handler+Thread适合进行大框架的异步处理,而asynTask适用于小型简单的异步处理。以上都是个人观点+理解。有新观点请指出。
2、Looper源码分析
Looper主要有prepare()和loop()两种方法
2.1 prepare()
1 public static final void prepare() { 2 if (sThreadLocal.get() != null) { 3 throw new RuntimeException("Only one Looper may be created per thread"); 4 } 5 sThreadLocal.set(new Looper(true)); 6 }
sThreadLocal是一个ThreadLocal对象,可以在一个线程中存储变量。可以看到,在第5行,将一个Looper的实例放入了ThreadLocal,并且2-4行判断了sThreadLocal是否为null,否则抛出异常。这也就说明了Looper.prepare()方法不能被调用两次,同时也保证了一个线程中只有一个Looper实例
2.2 looper()构造方法
1 private Looper(boolean quitAllowed) { 2 mQueue = new MessageQueue(quitAllowed); 3 mRun = true; 4 mThread = Thread.currentThread(); 5 }
在构造方法中,创建了一个MessageQueue(消息队列)。
2.3 loop()
1 public static void loop() { 2 final Looper me = myLooper(); 3 if (me == null) { 4 throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); 5 } 6 final MessageQueue queue = me.mQueue; 7 8 // Make sure the identity of this thread is that of the local process, 9 // and keep track of what that identity token actually is.10 Binder.clearCallingIdentity();11 final long ident = Binder.clearCallingIdentity();12 13 for (;;) {14 Message msg = queue.next(); // might block15 if (msg == null) {16 // No message indicates that the message queue is quitting.17 return;18 }19 20 // This must be in a local variable, in case a UI event sets the logger21 Printer logging = me.mLogging;22 if (logging != null) {23 logging.println(">>>>> Dispatching to " + msg.target + " "24 + msg.callback + ": " + msg.what);25 }26 27 msg.target.dispatchMessage(msg);28 29 if (logging != null) {30 logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);31 }32 33 // Make sure that during the course of dispatching the34 // identity of the thread wasn't corrupted.35 final long newIdent = Binder.clearCallingIdentity();36 if (ident != newIdent) {37 Log.wtf(TAG, "Thread identity changed from 0x"38 + Long.toHexString(ident) + " to 0x"39 + Long.toHexString(newIdent) + " while dispatching to "40 + msg.target.getClass().getName() + " "41 + msg.callback + " what=" + msg.what);42 }43 44 msg.recycle();45 }46 }
第2行:
public static Looper myLooper() {
return sThreadLocal.get();
}
方法直接返回了sThreadLocal存储的Looper实例,如果me为null则抛出异常,也就是说looper方法必须在prepare方法之后运行。
第6行:拿到该looper实例中的mQueue(消息队列)
13到45行:就进入了我们所说的无限循环。
14行:取出一条消息,如果没有消息则阻塞。
27行:使用调用 msg.target.dispatchMessage(msg);把消息交给msg的target的dispatchMessage方法去处理。Msg的target是什么呢?其实就是handler对象。
44行:释放消息占据的资源。
2.4 Looper主要作用:
- 与当前线程绑定,保证一个线程只会有一个Looper实例,同时一个Looper实例也只有一个MessageQueue。
- loop()方法,不断从MessageQueue中去取消息,交给消息的target属性的dispatchMessage去处理。
http://blog.csdn.net/itachi85/article/details/8035333
http://www.it165.net/pro/html/201404/12969.html
http://www.2cto.com/kf/201203/122729.html
http://blog.csdn.net/lmj623565791/article/details/38377229
- Handler机制
- Handler机制
- handler机制
- handler机制
- Handler机制
- Handler机制
- handler机制
- Handler机制
- handler机制
- Handler机制
- handler机制
- Handler机制
- Handler机制
- Handler机制
- handler机制
- handler机制
- Handler机制
- Handler机制
- Android版本信息及与Linux和Java的关系
- Android多媒体技术之音频播放
- OAuth机制原理(开放授权机制)
- Android多媒体之view,SurfaceView,GLSurfaceView
- Android多媒体技术之视频播放
- Handler机制
- Android内存管理机制
- Android之从TCP/IP、HTTP看Socket通信
- java设计模式——策略模式
- 《Android应用性能优化》3——电量、渲染
- 《Android应用性能优化》2——内存、CPU、性能测评
- RHEL7.2 安装Texlive2016时出现Can't locate Digest/MD5.pm的解决方法
- 《Android应用性能优化》1——代码
- Android4.0 Launcher 源码分析2——Launcher内容加载绑定详细过程