Android 开发不得不了解的Handler

前言

Android 开发离不开handler,那什么是handler呢?下面是google对handler的定义:
处理程序允许您发送和处理与线程的{@link MessageQueue}关联的{@link Message}和可运行对象。每个处理程序实例都与一个线程和该线程的消息队列相关联。

简单可以理解为消息传递的工具。

应用场景按功能可以分为两种:
1、延时执行;
2、在子线程通知更新UI;

Handler使用

以下根据我常用的方式介绍:

handler的初始化及接收:

 Handler mHandler = new Handler(new Handler.Callback() {
        @Override
        public boolean handleMessage(Message message) {
            switch (message.what) {
                case 100:
                    break;
                    }
       }
 });

handler发送消息:

1、发送空消息或延时执行:

mHandler.sendEmptyMessage(100);
//第一个参数what  第二个参数间隔时间毫秒值
mHandler.sendEmptyMessageDelayed(100,1000);

2、发送带值的消息或延时执行:

 Message message = handler.obtainMessage();
 message.what = 100;
 message.obj = new Object();
 mHandler.sendMessage(message);
 //第一个参数message  第二个参数间隔时间毫秒值
 mHandler.sendMessageDelayed(message,1000);

handler移除发送的消息:

在页面关闭时记得调用下面方法移除所有消息和监听,以防页面关闭了还有一些延迟操作未执行mHandler.removeCallbacksAndMessages(null);

移除指定what对应的消息
mHandler.removeMessages(int what);
传null 所有的消息和监听都会被移除
mHandler.removeCallbacksAndMessages(null);

Handler原理解析

handler实现主要涉及以下几个类:

Handler:消息处理者,负责向消息池中发送消息 (Handler.enqueueMessage) 和处理消息 (Handler.handleMessage) 。
Message:消息,产生的消息和生成的消息。
MessageQueue:消息队列,主要功能是向消息池投递信息 (MessageQueue.enqueueMessage) 和取走消息池的信息 (MessageQueue.next) 。
Looper: 死循环执行 (Looper.loop) ,检测是否有待处理的消息,然后按分发机制将消息分发给目标处理者。

Handler

查看handler的源码会发现handler有以下构造函数:

public Handler()
public Handler(Callback callback) 
public Handler(Looper looper) 
public Handler(Looper looper, Callback callback)
public Handler(boolean async)
public Handler(Callback callback, boolean async)
public Handler(Looper looper, Callback callback, boolean async)

handler主要实现发消息和处理接收消息,查看源码可以发现发消息无论执行那个方法最后都是执行sendMessageAtTime();
在这里插入图片描述
消息队列MessageQueue若为空会直接报错,不为空就会执行enqueueMessage();根据消息,延迟时间去消息队列查询消息
在这里插入图片描述

查看源码是细心点会看到如下代码,那SystemClock.uptimeMillis()是什么呢?它显示的是“系统启动到现在的毫秒数,不包含休眠时间。”
在这里插入图片描述
顺便看看其他获取时间的方法:
System.currentTimeMillis() // 从1970年1月1日 UTC到现在的毫秒数;
SystemClock.currentThreadTimeMillis();//当前线程运行的毫秒数。
SystemClock.uptimeMillis() // 从开机到现在的毫秒数(手机睡眠的时间不包括在内);
SystemClock.elapsedRealtime();//系统启动到现在的毫秒数,包含休眠时间。

Looper

Looper在消息机制里扮演着消息循环的角色,它不停的从消息队列里查看是否有新消息,如果有,则立即处理新消息,没有则一直阻塞在那里。
直接看两个片段的源代码:
在这里插入图片描述
从图可以看出,Looper初始化调用prepare方法,一个线程只能有一个looper,当此线程已有一个looper,在调用初始化时会抛出一个"Only one Looper may be created per thread"异常。
在这里插入图片描述
从图看到是一个死循环的,looper不停的从消息队列里查看是否有新消息,如果有,则立即处理新消息,没有就会跳出循环。

MessageQueue

MessageQueue消息队列,通过单向链表的数据结构存储消息或者删除消息,主要作用就是:插入和读取消息,每一次读取消息其实就是删除操作,主要的两个方法是enqueueMessage和next。直接看源码:主要看什么情况抛什么异常和大致执行逻辑

boolean enqueueMessage(Message msg, long when) {
        if (msg.target == null) {
            throw new IllegalArgumentException("Message must have a target.");
        }
        if (msg.isInUse()) {
            throw new IllegalStateException(msg + " This message is already in use.");
        }

        synchronized (this) {
            if (mQuitting) {
                IllegalStateException e = new IllegalStateException(
                        msg.target + " sending message to a Handler on a dead thread");
                Log.w(TAG, e.getMessage(), e);
                msg.recycle();
                return false;
            }

            msg.markInUse();
            msg.when = when;
            Message p = mMessages;
            boolean needWake;
            if (p == null || when == 0 || when < p.when) {
                // New head, wake up the event queue if blocked.
                msg.next = p;
                mMessages = msg;
                needWake = mBlocked;
            } else {
                // Inserted within the middle of the queue.  Usually we don't have to wake
                // up the event queue unless there is a barrier at the head of the queue
                // and the message is the earliest asynchronous message in the queue.
                needWake = mBlocked && p.target == null && msg.isAsynchronous();
                Message prev;
                for (;;) {
                    prev = p;
                    p = p.next;
                    if (p == null || when < p.when) {
                        break;
                    }
                    if (needWake && p.isAsynchronous()) {
                        needWake = false;
                    }
                }
                msg.next = p; // invariant: p == prev.next
                prev.next = msg;
            }

            // We can assume mPtr != 0 because mQuitting is false.
            if (needWake) {
                nativeWake(mPtr);
            }
        }
        return true;
    }

Message

Message相对简单,就是消息类,它实现了Parcelable序列化。
使用时尽量使用obtain方法获取Message对象,不要使用new的方法,那我们看看obtain方法做了什么操作呢:
在这里插入图片描述
从消息池中分配消息对象,避免重新创建新对象消耗更多的内存资源,除非消息池没有消息对象才会去创建新的对象。

ThreadLocal

handler为什么会用到ThreadLocal呢,ThreadLocal是在looper时用到的,不知道你有没有发现。
ThreadLocal有以下特性:
1、是一个线程内部的数据存储类,通过它可以在指定的线程中存储数据。
2、只有在指定的线程里才能获取到存储的数据,对于其他线程来说是获取不到的。

而我们再说looper时说了,一个线程只能有一个looper对象,已经有looper了再调用初始化时会抛出一个"Only one Looper may be created per thread"异常。这个时候就可以很方便的在不同的线程中通过ThreadLocal对Looper进行存取。

总结

handler机制就是handler将message对象发送到Looper的MessageQueue消息队列中,然后由Looper的loop方法轮询读取Message,然后调用Message的target传递给Handler的dispatchMessage()方法,将该消息回调到handleMessage方法中,执行更新操作。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值