Handle机制与源码分析

1.Handle主要成员

1.1 Handler实例:负责消息的发送与回调,一个线程可以有多个Handler

1.2 Message:消息实例,保存消息并持有Handler实例,存在MessageQueue中,一个线程可以有多个Message。

1.3 MessageQueue:消息队列,存放Handler发送的消息,供Looper使用,一个线程只能有一个MessageQueue。

1.4 Looper:消息遍历者,持有MessageQueue,从MessageQueue中循环取出Message。一个线程只能有一个Looper。

2. 基本使用

//创建Handle
Handler handler = new Handler(getMainLooper()){
    @Override
    public void handleMessage(@NonNull Message msg) {
        super.handleMessage(msg);
        if(msg.what == 1){
            //2.接收到消息,进行处理
        }
    }
};
//1.在需要的时候调用。发送消息
handler.sendEmptyMessage(1);

Handler使用我们一般就只需要做两步:发送消息与接收回调。接下去我们就沿着这两个来看源码。先看一下Handle的流程图。

流程图

3. Handle机制分析

3.1 发送Message

可以看到,不管调用handle的入口是哪个,最终的结果都是调用MessageQueue.enqueueMessage()方法。没什么好说的,唯一需要注意的就是long uptimeMillis在后面的队列中需要用到。

public final boolean sendMessage(@NonNull Message msg) {
    return sendMessageDelayed(msg, 0);
}
public final boolean sendMessageDelayed(@NonNull Message msg, 
long delayMillis) {
    if (delayMillis < 0) {
        delayMillis = 0;
    }
    return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
public boolean sendMessageAtTime(@NonNull Message msg, long uptimeMillis) {
    MessageQueue queue = mQueue;
    //...
    //这里需要注意一下uptimeMillis在后面队列排序中需要用到
    return enqueueMessage(queue, msg, uptimeMillis);
}
private boolean enqueueMessage(@NonNull MessageQueue queue,
 @NonNull Message msg,
        long uptimeMillis) {
    msg.target = this;
    msg.workSourceUid = ThreadLocalWorkSource.getUid();

    if (mAsynchronous) {
        msg.setAsynchronous(true);
    }
    //不管从哪里开始,最终都会走到这里
    return queue.enqueueMessage(msg, uptimeMillis);
}

接下来我们来看看MessageQueue里的enqueueMessage发生了什么。可以看到,mMessages其实就是Handle的消息队列了,mMessages作为队头,内部直接引用队列的第二项Message,然后第二项引用第三项,以此类推就形成了一个队列。举一个通俗的例子来说明,现在小明一家人排成一列(队列),爸爸在最前面(队头),爸爸牵着妈妈,妈妈牵着姐姐,姐姐牵着小明,小明...。

boolean enqueueMessage(Message msg, long when) {
    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);
            //线程死亡,回收Message,不再往下执行
            msg.recycle();
            return false;
        }
        msg.markInUse();
        msg.when = when;
        //直接拿到队头
        Message p = mMessages;
        boolean needWake;
        if (p == null || when == 0 || when < p.when) {
            //when就是我们前面说需要注意的时间uptimeMillis
            //如果为0就是不延时,直接加入到队头
            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;
}

3.2 取出Message

创建Handler的之前要先调Looper.prepare()创建Looper,然后创建Handler之后调Looper.loop()。我们来看一下主线程的Looper是在什么创建的,我们App的入口就是ActivityThread中的main函数,在main函数中创建Looper。

public static void main(String[] args) {
    //其他的不看,只看Looper相关
    //....
    //创建主线程Looper
    Looper.prepareMainLooper();

    //创建主线程
    ActivityThread thread = new ActivityThread();
    thread.attach(false, startSeq);

    if (sMainThreadHandler == null) {
        //主线程的Handle
        sMainThreadHandler = thread.getHandler();
    }
    //......
    //直接调用loop
    Looper.loop();
    //主线程中Looper.loop死循环是不能退出的
    //如果意外退出,说明程序有问题,直接报错
    throw new RuntimeException("Main thread loop unexpectedly exited");
}

看看Looper中是怎么创建主线程的Looper。

public static void prepareMainLooper() {
    prepare(false);
    //加锁保证只创建一个Looper
    synchronized (Looper.class) {
        if (sMainLooper != null) {
            //....
        }
        sMainLooper = myLooper();
    }
}

private static void prepare(boolean quitAllowed) {
    if (sThreadLocal.get() != null) {
        throw new RuntimeException("Only one Looper may be created per thread");
    }
    //最终在这里创建了一个Looper
    //子线程也是在这里创建Looper
    sThreadLocal.set(new Looper(quitAllowed));
}

刚刚我们看到了线程创建的时候就直接创建了Looper,并调用loop()。现在来看一下loop()中的代码。在loop()中开启一个死循环,不断的轮询MessageQueue取出Message,Handler.dispatchMessage(Message msg)将消息发调用Looper持有的送给handler的回调handlerMessage();

public static void loop() {
    final Looper me = myLooper();
    //....
    
    //拿到消息队列
    final MessageQueue queue = me.mQueue;

    //...
    //开启死循环
    for (;;) {
        //拿到消息队列中需要的处理的消息
        Message msg = queue.next(); // might block
        if (msg == null) {
            //没有消息了就退出循环进入休眠
            return;
        }

        //......
        
        try {
            //msg.target就是Handle
            //调用handle.dispatchMessage处理消息
            msg.target.dispatchMessage(msg);
            if (observer != null) {
                observer.messageDispatched(token, msg);
            }
            dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
        } catch (Exception exception) {
            //错误处理
        }

        //...
        
        //回收消息
        msg.recycleUnchecked();
    }
}

刚刚看了loop()其实最终目的就是为了调用handle.dispatchMessage,接下来我们看一下handle.dispatchMessage做了什么。可以看到就是调用了handleCallback回调或者handleMessage回调。熟悉吗,就是我们创建Handle时的回调。

public void dispatchMessage(@NonNull Message msg) {
    if (msg.callback != null) {
        //回调1
        handleCallback(msg);
    } else {
        if (mCallback != null) {
            //回调2
            if (mCallback.handleMessage(msg)) {
                return;
            }
        }
        //回调3
        handleMessage(msg);
    }
}

就这样,关于Handle的消息机制就完成了

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值