Handler用法详解
2016-07-12 13:49
363 查看
Handler 简介:
主要作用:1>在新起的线程中发送消息
2>在主线程中(UI线程,main thread)中接收消息,并更新UI。
原因:Android4.0后,Google官方禁止在主线程中进行耗时操作,避免引起ANR,提高用户体验。假设不用Handler的话,改用加锁方案,但是稍微一想就会发现,这样的方式会无限增加代码的复杂度,增加代码的耦合,而且锁问题还会引起别的不稳定因素。
用法:
构建Handler的成员变量,重写handleMessage(android.os.Message msg)方法,开启子线程或在回调中发送消息方法一般有:sendEmptyMessage或者obtainMessage,这两者的区别主要在与obtainMessage可以避免创建对象,从而减少内存的开销。
Handler中一共涉及到四个对象:Handler、Message、Looper、MessageQueue。这四者的关系和原理:
Message:Handler发送、接受和处理的消息对象;
Looper:每个线程都有一个Looper对象,负责无限循环的去从消息队列中取消息,并将读取到的消息发送给Handler对象去处理;
MessageQueue:消息队列,它采用先进先出的方式去管理Message,程序在创建Looper对象时,会在他的构造器中创建MessageQueue,源码:
Handler:作用有两个,发送消息和处理消息,Handler发送的消息必须送到指定的MessageQueue,而MessageQueue是由Looper负责管理的,因此要想Handler正常工作,必须在当前线程中有一个Looper对象这里分为两种情况:
1>主线程(UI线程),系统已经初始化了一个Looper对象,因此程序直接创建Handler即可
2>程序员自己创建的子线程,这时,程序员必须创建一个Looper对象,并启动它。
创建Looper使用:Looper.prepare(),查看源码:
通过方法调用,第9行创建Looper对象,创建Looper对象时同时会创建MessageQueue对象(第13行)。此外,可以看出prepare()允许一个线程最多有一个Looper被创建。
然后调用Looper的looper()方法来启动它,looper()使用一个死循环不断取出MessageQueue中的消息,并将消息发送给对应的Handler进行处理。下面是Looper类中looper()方法的部分源码:
很明显第1行用了一个死循环,第2行从queue中取出Message,第15行通过dispatchMessage(Message msg)方法将消息发送给Handler。
主要作用:1>在新起的线程中发送消息
2>在主线程中(UI线程,main thread)中接收消息,并更新UI。
原因:Android4.0后,Google官方禁止在主线程中进行耗时操作,避免引起ANR,提高用户体验。假设不用Handler的话,改用加锁方案,但是稍微一想就会发现,这样的方式会无限增加代码的复杂度,增加代码的耦合,而且锁问题还会引起别的不稳定因素。
用法:
构建Handler的成员变量,重写handleMessage(android.os.Message msg)方法,开启子线程或在回调中发送消息方法一般有:sendEmptyMessage或者obtainMessage,这两者的区别主要在与obtainMessage可以避免创建对象,从而减少内存的开销。
Handler中一共涉及到四个对象:Handler、Message、Looper、MessageQueue。这四者的关系和原理:
Message:Handler发送、接受和处理的消息对象;
Looper:每个线程都有一个Looper对象,负责无限循环的去从消息队列中取消息,并将读取到的消息发送给Handler对象去处理;
MessageQueue:消息队列,它采用先进先出的方式去管理Message,程序在创建Looper对象时,会在他的构造器中创建MessageQueue,源码:
private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread(); }
Handler:作用有两个,发送消息和处理消息,Handler发送的消息必须送到指定的MessageQueue,而MessageQueue是由Looper负责管理的,因此要想Handler正常工作,必须在当前线程中有一个Looper对象这里分为两种情况:
1>主线程(UI线程),系统已经初始化了一个Looper对象,因此程序直接创建Handler即可
2>程序员自己创建的子线程,这时,程序员必须创建一个Looper对象,并启动它。
创建Looper使用:Looper.prepare(),查看源码:
1 public static void prepare() { 2 prepare(true); 3 } 4 5 private static void prepare(boolean quitAllowed) { 6 if (sThreadLocal.get() != null) { 7 throw new RuntimeException("Only one Looper may be created per thread"); 8 } 9 sThreadLocal.set(new Looper(quitAllowed)); 10 } 11 12 private Looper(boolean quitAllowed) { 13 mQueue = new MessageQueue(quitAllowed); 14 mThread = Thread.currentThread(); 15 }
通过方法调用,第9行创建Looper对象,创建Looper对象时同时会创建MessageQueue对象(第13行)。此外,可以看出prepare()允许一个线程最多有一个Looper被创建。
然后调用Looper的looper()方法来启动它,looper()使用一个死循环不断取出MessageQueue中的消息,并将消息发送给对应的Handler进行处理。下面是Looper类中looper()方法的部分源码:
1 for (;;) { 2 Message msg = queue.next(); // might block 3 if (msg == null) { 4 // No message indicates that the message queue is quitting. 5 return; 6 } 7 8 // This must be in a local variable, in case a UI event sets the logger 9 Printer logging = me.mLogging; 10 if (logging != null) { 11 logging.println(">>>>> Dispatching to " + msg.target + " " + 12 msg.callback + ": " + msg.what); 13 } 14 15 msg.target.dispatchMessage(msg); 16 17 if (logging != null) { 18 logging.println("<<<<< Finished to " + msg.target + " " + msg.callback); 19 } 20 21 // Make sure that during the course of dispatching the 22 // identity of the thread wasn't corrupted. 23 final long newIdent = Binder.clearCallingIdentity(); 24 if (ident != newIdent) { 25 Log.wtf(TAG, "Thread identity changed from 0x" 26 + Long.toHexString(ident) + " to 0x" 27 + Long.toHexString(newIdent) + " while dispatching to " 28 + msg.target.getClass().getName() + " " 29 + msg.callback + " what=" + msg.what); 30 } 31 32 msg.recycleUnchecked(); 33 }
很明显第1行用了一个死循环,第2行从queue中取出Message,第15行通过dispatchMessage(Message msg)方法将消息发送给Handler。
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析
- android searchView的关闭事件
- SourceProvider.getJniDirectories