Android-Handler传递消息机制详解

Handler

Handler机制是Android中基于单线消息队列模式的一套线程消息机制。

Handler基础使用

子线程中创建Handler

     		Looper.prepare();//让线程与Looper关联
            h = new Handler(Looper.myLooper()){
                @Override
                public void handleMessage(@NonNull Message msg) {
                    super.handleMessage(msg)}
            };
            Looper.loop();//不加则不能发送消息,启动循环

sendMessageAtTime以及sendMessageDelayed()区别

sendMessageDelayed()参数直接添加延迟多少毫秒,有sendMessageAtTime()源码分析可知延迟多少秒参数应为delayMillis+SystemClock.uptimeMillis();
原因:SystemClock.uptimeMillis()是获取系统从开机启动到现在的时间,期间不包括休眠的时间,这里获得到的时间是一个相对的时间,而不是通过获取当前的时间(绝对时间)。
而之所以使用这种方式来计算时间,而不是获得当前currenttime来计算,在于handler会受到阻塞,挂起状态,睡眠等,这些时候是不应该执行的;如果使用绝对时间的话,就会抢占资源来执行当前handler的内容,显然这是不应该出现的情况,所以要避免

sendMessageAtTime()源码:

 public boolean sendMessageAtTime(@NonNull 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;
        }
        return enqueueMessage(queue, msg, uptimeMillis);//所有send方法都指向这个方法
    }

sendMessageDelayed()源码:

  public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }

消息机制原理

Handler主要用于异步消息的处理:当发出一个消息之后,首先进入一个消息队列,发送消息的函数即刻返回,而另外一个部分在消息队列中逐一将消息取出,然后对消息进行处理,也就是发送消息和接收消息不是同步的处理。 这种机制通常用来处理相对耗时比较长的操作。
原理图一

Handler通信四大类

Message源码分析

成员变量:

  • public int what;//消息标识id
  • public int arg1;//保存int数据
  • public int arg2;//保存int数据
  • public Object obj;//保存任意数据
  • long when;//记录应该被处理的时间值
  • Handler target;//用来处理消息的Handler对象,就是发送消息的handler,同样用来在Looper识别handler
  • Runnable callback;//用来处理消息的回调器
  • Message next;//指向下一个message用来形成一个链表
  • private static Message sPool;//用来缓存处理过的Message,以便复用
  • Message obtain();

Handler源码分析

sendMessage,postMessage:本质就是将消息添加到消息队列(MessageQueue.enqueueMessage())

Looper识别handler


 private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
//会把this赋值给msg.target,此时target就指向当前Handler
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
//之后调用MessageQueue的enqueueMessage分发消息进行处理
        return queue.enqueueMessage(msg, uptimeMillis);
    }

Lopper类源码分析

Looper.prepare():该方法在线程中将 Looper 对象定义为 ThreadLocal 对象,使得 Looper 对象成为该线程的私有对象,一个线程最多仅有一个 Looper。并在这个 Looper 对象中维护一个消息队列 MessageQueue 和持有当前线程的引用,因此 MessageQueue 也是线程私有。
Looper.loop():

public static void loop() {
    // 得到当前线程的Looper对象
    final Looper me = myLooper();
    if (me == null) {
        // 线程没有调用Looper.prepare(),所以没有Looper对象
        throw new RuntimeException(
            "No Looper; Looper.prepare() wasn't called on this thread.");
    }
    // 得到当前消息队列
    final MessageQueue queue = me.mQueue;

    ...

    // 开始循环
    for (;;) {
        // 从消息队列中获取下一个Message,该方法可以被阻塞
        Message msg = queue.next();
        
        ...
        
        // 将Message推送到Message中的target处理
        // 此处的target就是发送该Message的Handler对象
        msg.target.dispatchMessage(msg);
        
        ...
        
        // 回收Message,这样就可以通过Message.obtain()复用
        msg.recycleUnchecked();
    }
}

MessageQueue(优先级队列),根据时间进行排序类源码分析

MessageQueue消息队列里面,添加的每一个消息都有对应的线程

1.插入消息到消息队列 2.唤醒Looper中等待的线程 (如果是及时消息并且线程是阻塞状态)
enqueueMessage源码分析:

boolean enqueueMessage(Message msg, long when) {
        synchronized (this) {
            if (msg.isInUse()) {
                throw new IllegalStateException(msg + " This message is already in use.");
            }

            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) {
                msg.next = p;
                mMessages = msg;
                needWake = mBlocked;
            } else {
                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;
            }
            if (needWake) {
                nativeWake(mPtr);
            }
        }
        return true;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值