Android Handler机制

Handler机制分析

Handler核心类

核心类说明
Message消息对象,存放数据
MessageQueue消息队列,存放Message,按时间顺序排列的优先级队列
Handler主线程与子线程的通信媒介,发送和处理Message
LooperMessageQueue与Handler的通信媒介,从MessageQueue读取Message,分配给Handler处理

Handler机制分析

Handler基本使用

Handler mHandler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
        //TODO 用户处理
    }
};
Message message = Message.obtain();
mHandler.sendMessage(message);

Handler#enqueueMessage()

Handler中sendMessage/postXXX方法最终都会调用Handler#enqueueMessage(),再将消息交给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;
    }
    return enqueueMessage(queue, msg, uptimeMillis);
}

//最终都会执行enqueueMessage()
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
    //Message对象持有Handler引用
    msg.target = this;
    if (mAsynchronous) {
        msg.setAsynchronous(true);
    }
    //MessageQueue将消息插入消息队列中
    return queue.enqueueMessage(msg, uptimeMillis);
}

MessageQueueue#enqueueMessage()

MessageQueue接收到消息,按时间优先级存放入消息队列里

//将Message插入消息队列中
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;
        //mMessage是一个Message对象
        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对象
            Message prev;
            //死循环
            //消息队列里有消息,则根据消息发送的时间插入队列中
            for (;;) {
                prev = p;
                //获取链表的下一个                
                p = p.next;
                if (p == null || when < p.when) {
                    //跳出循环
                    break;
                }
                if (needWake && p.isAsynchronous()) {
                    needWake = false;
                }
            }
            //将消息插入合适的位置
            msg.next = p; 
            prev.next = msg;
        }

        //是否需要唤醒操作
        if (needWake) {
            nativeWake(mPtr);
        }
    }
    return true;
}

Looper#loop()

Looper的loop()方法一直遍历消息队列,会调用MessageQueue#next()获取Message对象,如果有消息就立即取出来,否则进入睡眠阻塞,获取到的消息会交给Handler#dispatchMessage()处理

//开启消息循环
public static void loop() {
    //获取当前线程的Looper对象
    final Looper me = myLooper();
    //若没有调用Looper.prepare()创建Looper,则会报错
    if (me == null) {
        throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
    }
    //获取MessageQueue对象
    final MessageQueue queue = me.mQueue;
    
    //开启死循环
    for (;;) {
        //从MesageQueue中获取消息,可能会被阻塞
        Message msg = queue.next();
        //如果没有新消息就结束消息循环
        if (msg == null) {
            return;
        }
        //分发消息给Handler处理
        msg.target.dispatchMessage(msg);
        //释放资源,消息回收并放入消息池
        msg.recycleUnchecked();
    }
}

MessageQueue#next()

MessageQueue中的next()方法会从消息队列里获取消息

//取出消息
Message next() {  
    //该参数用于判断消息队列中是否有消息
    //-1:一直阻塞不会超时;0:立即返回;>0:最长阻塞,如有程序唤醒立即返回
    int nextPollTimeoutMillis = 0;
    for (;;) {
        if (nextPollTimeoutMillis != 0) {
            Binder.flushPendingCommands();
        }
        
        //native层,nextPollTimeoutMillis为-1,消息队列处于等待状态
        nativePollOnce(ptr, nextPollTimeoutMillis);

        synchronized (this) {
            final long now = SystemClock.uptimeMillis();
            Message prevMsg = null;
            Message msg = mMessages;
            //从消息队列中取出消息
            if (msg != null) {
                if (now < msg.when) {
                    nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                } else {
                    //取出消息
                    mBlocked = false;
                    if (prevMsg != null) {
                        prevMsg.next = msg.next;
                    } else {
                        mMessages = msg.next;
                    }
                    msg.next = null;
                    if (DEBUG) Log.v(TAG, "Returning message: " + msg);
                    msg.markInUse();
                    return msg;
                }
            } else {
                //若消息队列中无数据,则设置为-1
                //下次循环时,消息队列处于等待状态
                nextPollTimeoutMillis = -1;
            }
        }
    }
}

Handler#dispatchMessage()

public void dispatchMessage(@NonNull Message msg) {
    if (msg.callback != null) {
        //交给Message的callback处理
        handleCallback(msg);
    } else {
        if (mCallback != null) {
            //交给Handler的callback处理
            if (mCallback.handleMessage(msg)) {
                return;
            }
        }

        //交给重写的handleMessage()处理
        handleMessage(msg);
    }
}

Handler机制流程图及总结

在这里插入图片描述

  • Handler发送一个消息,会执行sendMessage/post等方法都会交给Handler#enqueueMessage()处理,接着执行MessageQueue#enqueueMessage()将消息放入消息队列中
  • Looper执行loop()方法,这是一个死循环,会一直调用MessageQueue#next()从消息队列中读取消息,当消息队列有消息时会被唤醒并读取消息,当消息队列没有消息时会睡眠式阻塞
  • Looper读取到消息会交给Handler#dispatchMessage()处理,最终分发给Handler#dispatchMessage()处理

常见问题

线程、Handler、Looper、MessageQueue 对应关系

  • 一个线程可以有多个Handler:我们可以在一个线程中创建多个Handler对象

  • 一个线程对应一个Looper:在主线程执行时,会调用Looper.prepareMainLooper()会创建主线程的Looper,通过ThreadLocal保持和获取Looper对象

  • Looper内部维护一个MessageQueue:创建Looper时会创建MessageQueue

  • 一个Handler对应一个Looper:Handler创建时会调用Looper#myLooper()获取Looper对象

Handler内存泄漏问题

内存泄露原因:内部类的Handler会持有外部类的引用,Message对象持有Handler的引用,如果Mesage没有被处理,会一直存放在MessageQueue里,这样会造成外部类不能得到及时回收,造成内存泄漏

解决办法:

  • 及时清理消息队列中的垃圾消息
  • 内部类使用static和WeakReference

Handler内存泄漏解决方案

子线程中使用Handler

在子线程中使用Handler,会抛出异常java.lang.RuntimeException: Can't create handler inside thread Thread[Thread-2,5,main] that has not called Looper.prepare()

这是因为子线程没有Looper,必须先执行Looper.prepare()创建Looper对象,然后再执行Looper.loop()开启遍历消息队列

Message创建方式

推荐使用Message.obtain()创建Message对象,该方法从消息池里获取数据,性能较高

Handler如何保障线程安全

MessageQueue消息队列在存数据和取数据都是用synchronized加锁

Looper死循环为什么不会导致ANR

ANR指应用无响应,在一段时间内无法处理任务,如:键盘输入、触摸屏幕5s内没有响应,广播10s内没有执行完

Looper死循环不会导致应用卡死,在没有消息时会阻塞线程并进入休眠释放CPU资源,当有消息时会被立即唤醒

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值