Android学习之Handler使用小结
2016-06-17 14:10
489 查看
Handler的使用大家都很熟悉,今天做一下关于Handler的总结,方便以后使用。
为什么用Handler
Handler的作用:
Handler和Looper
上面理论上看起来理解不是很理想,下面我找了几张图来方便理解。
Looper.prepare():
可以看出通过prepare()方法,创建了线程和消息队列。下面我们看源码
prepare()会new Looper()创建一个Looper对象,对象里面分别又创建了线程和MQ。由此可知一个Thread只能有一个Looper对象对应一个MQ,三者一一对应。
Looper.loop():
Looper会不断从MQ中取出消息头执行,并推送给Handler执行。
Handler发送消息:
一个线程可以有多个Handler,但是只能有一个Looper!Handler发送消息通过Looper添加到MQ。
Handler处理消息:
Looper取出消息头,Handler执行,完毕后返回Looper继续执行。
总流程:
使用案例
子线程向主线程发送消息:
主线程向子线程发送消息:
主线程发送:
Handler的post()方法:
runOnUiThread()方法:
post和runOnUiThread都可以在子线程中更新UI,但是实际上他们是将消息post到UI线程中处理,所以run()里面不能做耗时操作。
为什么用Handler
UI线程是非安全线程,不能进行耗时操作,子线程做耗时操作,不能更新UI,否则会出现程序长时间假死状态,即ANR,程序无响应异常。 为了解决以上问题,Android设计了Handler机制,由Handler来负责与子线程进行通讯,从而让子线程与主线程之间建立起协作的桥梁,使Android的UI更新的问题得到完美的解决。
Handler的作用:
1. 在新启动的线程中发送消息; 2. 在主线程中获取、处理消息。
Handler和Looper
Message:消息体 Handler:负责发送消息sendMessage(message),接收消handleMessage(Message msg) Looper:消息泵,用来管理特定线程内对象之间的消息交换,一个线程可以产生一个Looper对象,由它来管理此线程里的Message Queue(消息队列)。主要包含两个方法Looper.prepare(),Looper.loop() Message Queue:消息队列,存放线程放入的消息 UI线程:主线程,启动的时候会创建消息队列已经 给线程创建一个消息循环Looper.prepare()
@Override public void run() { try { // preparing a looper on current thread // the current thread is being detected implicitly Looper.prepare(); // now, the handler will automatically bind to the // Looper that is attached to the current thread // You don't need to specify the Looper explicitly handler = new Handler(); // After the following line the thread will start // running the message loop and will not normally // exit the loop unless a problem happens or you // quit() the looper (see below) Looper.loop(); } catch (Throwable t) { Log.e(TAG, "halted due to an error", t); } }
上面理论上看起来理解不是很理想,下面我找了几张图来方便理解。
Looper.prepare():
可以看出通过prepare()方法,创建了线程和消息队列。下面我们看源码
public class Looper { // 每个线程中的Looper对象其实是一个ThreadLocal,即线程本地存储(TLS)对象 private static final ThreadLocal sThreadLocal = new ThreadLocal(); // Looper内的消息队列 final MessageQueue mQueue; // 当前线程 Thread mThread; // 。。。其他属性 // 每个Looper对象中有它的消息队列,和它所属的线程 private Looper() { mQueue = new MessageQueue(); mRun = true; mThread = Thread.currentThread(); } // 我们调用该方法会在调用线程的TLS中创建Looper对象 public static final void prepare() { if (sThreadLocal.get() != null) { // 试图在有Looper的线程中再次创建Looper将抛出异常 throw new RuntimeException("Only one Looper may be created per thread"); } sThreadLocal.set(new Looper()); } // 其他方法 }
prepare()会new Looper()创建一个Looper对象,对象里面分别又创建了线程和MQ。由此可知一个Thread只能有一个Looper对象对应一个MQ,三者一一对应。
Looper.loop():
Looper会不断从MQ中取出消息头执行,并推送给Handler执行。
Handler发送消息:
一个线程可以有多个Handler,但是只能有一个Looper!Handler发送消息通过Looper添加到MQ。
Handler处理消息:
Looper取出消息头,Handler执行,完毕后返回Looper继续执行。
总流程:
使用案例
子线程向主线程发送消息:
new Thread(new Runnable() { @Override public void run() { MyHandler handler = new MyHandler(getMainLooper()); Message message = new Message(); message.obj = "子线程发送的消息"; handler.sendMessage(message); } }).start(); class MyHandler extends Handler { public MyHandler(Looper looper) { super(looper); } @Override public void handleMessage(Message msg) { super.handleMessage(msg); Log.e("TAG", msg.obj.toString()); } }
主线程向子线程发送消息:
class TestThread extends Thread { private Handler handler; @Override public void run() { super.run(); Looper.prepare(); handler=new Handler(getMainLooper()){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); Log.e("TAG",msg.obj.toString()); } }; Looper.loop(); } }
主线程发送:
new TestThread().handler.sendEmptyMessage(0);
Handler的post()方法:
new Thread(){ @Override public void run() { mHandler.post(new Runnable() { @Override public void run() { //更新UI } }); }; }.start();
runOnUiThread()方法:
new Thread(){ public void run() { mActivity.runOnUiThread(new Runnable() { @Override public void run() { //更新UI } }); }; }.start();
post和runOnUiThread都可以在子线程中更新UI,但是实际上他们是将消息post到UI线程中处理,所以run()里面不能做耗时操作。
相关文章推荐
- 使用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