Handler浅析——学习笔记
来源:互联网 发布:sql中union的用法 编辑:程序博客网 时间:2024/06/07 07:14
1、概述
- handler是android给我们提供用来更新UI的一套机制,也是一套消息处理的机制,我们可以发送消息,也可以通过它处理消息。
2、常见异常
在子线程中进行更新UI操作会抛出
android.view.ViewRootImpi$CalledFromWrongThreadException
解决办法:子线程发消息给主线程handler去修改UI该异常发生在子线程创建Handler时,因为handler需要绑定一个Looper,主线程默认创建了一个Looper所以直接创建handler不会报错,子线程不会默认创建Looper,所以要手动创建出Looper
Can’t create handler inside thread that has not called Looper.prepare()
解决办法:子线程创建Handler之前调用Looper.prepare(),之后调用Looper.loop()
3、常见用法
post();postDelayed();sendMessage();sendMessageDelayed();Handler handler = new Handler(new Callback(){ @Override public boolean handlerMessage(Message msg){ // 这个方法可以截获消息对象,返回值为true,表示截获 return false; }}){ @Override public void handlerMessage(Message msg){ // 消息如果没有被截获,这个方法正常处理消息 }}
4、原理
- android使用handler最根本的目的就是解决多线程并发问题.
假设如果在一个Activity当中,有多个线程去更新UI,并且都没有加锁机制。就会产生更新界面错乱
如果对更新UI的操作都进行加锁处理,又会产生性能下降 - Handler封装了消息的发送(主要包括消息发送给谁)
Looper
1.内部包含一个消息队列也就是MessageQueue,所有的Handler发送的消息都走向这个消息队列
2.Looper.Looper方法,就是一个死循环,不断的从MessageQueue取消息,如果有消息就处理消息,没有就阻塞。 - MessageQueue,就是一个消息队列,可以添加消息,并处理消息
- Handler也很简单,内部会跟Looper进行关联,也就是说在Handler的内部可以找到Looper,找到了Looper也就找到了MessageQueue,在Handler中发送消息,其实就是向MessageQueue队列中发送消息。
handler负责发送消息,Looper负责接收Handler发送的消息,并直接把消息回传给handler自己,MessageQueue就是一个存储消息的容器
5、handler源码主要逻辑
- 发送消息
handler.sendMessage(msg);
- 插入消息到MessageQueue中
public boolean sendMessageAtTime(Message msg, long uptimeMillis) { MessageQueue queue = mQueue; if (queue == null) { RuntimeException e = new RuntimeException( this + " sendMessageAtTime() called with no mQueue"); Log.w("Looper", e.getMessage(), e); return false; } // 这一步是插入消息到MessageQueue中 return enqueueMessage(queue, msg, uptimeMillis); }
- 在插入到队列过程中,设置target为当前handler
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { msg.target = this; if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis); }
- Looper轮询,在Looper.loop()方法中,死循环,从MessageQueue取出消息
public static void loop() { final Looper me = myLooper(); if (me == null) { throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); } final MessageQueue queue = me.mQueue; Binder.clearCallingIdentity(); final long ident = Binder.clearCallingIdentity(); for (;;) { Message msg = queue.next(); // might block if (msg == null) { return; } try { // target就是发消息的handler msg.target.dispatchMessage(msg); } finally { if (traceTag != 0) { Trace.traceEnd(traceTag); } } } }
- 跳转到Handler的dispatchMessage方法
public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } // 回调到handlerMessage handleMessage(msg); } }
总的来说
1、首先Looper.prepare()在本线程中保存一个Looper实例,然后该实例中保存一个MessageQueue对象;因为Looper.prepare()在一个线程中只能调用一次,所以MessageQueue在一个线程中只会存在一个。
2、Looper.loop()会让当前线程进入一个无限循环,不端从MessageQueue的实例中读取消息,然后回调msg.target.dispatchMessage(msg)方法。
3、Handler的构造方法,会首先得到当前线程中保存的Looper实例,进而与Looper实例中的MessageQueue想关联。
4、Handler的sendMessage方法,会给msg的target赋值为handler自身,然后加入MessageQueue中。
5、在构造Handler实例时,我们会重写handleMessage方法,也就是msg.target.dispatchMessage(msg)最终调用的方法。
在子线程中创建一个handler
class MyThread extends Thread{ public Handler handler; @Override public void run() { Looper.prepare(); handler = new Handler(){ @Override public void handleMessage(Message msg) { System.out.println("currentThread:" + Thread.currentThread()); } }; Looper.loop(); } };
- Handler浅析——学习笔记
- Aandroid学习笔记—Handler
- Android学习笔记——Handler
- marsandroid学习笔记——Handler
- android学习笔记——Handler
- Android学习笔记 — Handler小解
- Android学习笔记8——Handler使用
- Android学习笔记9——Handler初步
- Android学习笔记10——Handler(二)
- Android学习笔记(五)——handler的使用
- Android学习笔记06——handler的使用
- Handler工作机制【简】——学习笔记
- android学习笔记——Handler用法总结
- <Android学习笔记二>——Handler的实现
- Android学习笔记——Handler消息分发
- 学习笔记(三)——有用的Handler
- 新手Android学习笔记 07——认识Handler
- 【安卓笔记】Handler+Thread使用浅析
- LeetCode
- PHP防止精度丢失
- 检测linux系统支持的soket选项
- 安装nginx服务器用于rtmp(ios端)推流测试
- Jenkins 搭建C++持续集成环境
- Handler浅析——学习笔记
- Hadoop安装及开发环境配置
- 原生h5表单验证
- Tomcat获取Nginx反向代理的客户端IP地址
- Logdump Reference for Oracle GoldenGate12c (12.2.0.1)中文翻译
- OBM,ODM,OEM分别指什么
- javascript中 对象创建的三种方式及其调用方法
- Activity生命周期
- qt之不能打开源代码的问题