Handler消息机制源码分析

    public static final Looper myLooper() {
        return (Looper)sThreadLocal.get();
    }

先来个Handler执行过程的总结:

1、 Looper.prepare()方法

为当前线程绑定looper,

在looper构造方法中创建一个messageQueue

2、 创建handler 重并写handleMessage方法

3、 使用handler发送消息,最终消息都会发送至messageQueue对象中,在messageQueue当中,所有的message按应该执行的时间的先后顺序,从小到大排列

4、Looper.loop()

在此方法中,开启死循环,不断的从messageQueue中取出应该执行的message,并执行message 对应的handler中的dispatchMessage方法,即,执行我们重写的handleMessage方法

参照以上分析在子线程中创建Handler对象:

	new Thread(){
	    @Override
	    public void run() {
		Message msg = Message.obtain();
		Looper.prepare();//若没有调用此方法则抛出异常 Can't create handler inside thread that has not called Looper.prepare()
		Handler handler2 = new Handler(){
		    public void handleMessage(Message msg) {
			Toast.makeText(MainActivity.this, "收到子线程message消息", 0).show();
		    };
		};
		handler2.sendMessage(msg);
		Looper.loop();
	    }
	}.start();

对比在主线程中创建Handler实例对象我们发现,在子线程中创建Handler对象需要在创建前调用Looper.prepare()方法在创建后调用Looper.loop方法,那究竟这两个方法是做什么的呢?

先看看系统的Looper.prepare方法:

public static final void prepare() {

        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
		// 为当前线程绑定一个looper对象,以sThreadLocal为key
        sThreadLocal.set(new Looper());
    }

即:调用Looper.prepare方法时为当前线程绑定了一个Looper对象,所以Looper.prepare方法只能调用一次,即一个线程只能有一个Looper对象

再看看Looper的构造方法:

 private Looper() {
        mQueue = new MessageQueue();
    }

因为一个线程只能有一个Looper对象,所以一个线程也只能有一个MessageQueue对象

先让我们看看Handler的构造方法:

public Handler() {
	//获得当前线程的looper对象
        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread that has not called Looper.prepare()");
        }
		// 获得looper中MessageQueue的引用
        mQueue = mLooper.mQueue;
    }

再看看系统的Looper.myLooper方法:即获取调用Looper.prepare方法时保存在sThreadLoad的Looper对象,所以Looper.prepare方法要在new Handler方法前调用

    public static final Looper myLooper() {
        return (Looper)sThreadLocal.get();
    }

即:当创建Handler时会先调用Looper.myLooper()方法获取当前线程的Looper对象,如果Looper==null,则抛出异常

通过以上两个方法,当前线程的唯一Looper对象和MessageQueue对象都已创建,接下来该sendMessage了

查看系统源码可知:sendEmptyMessage等,发送信息的方法,最终都是调用了SendMessageAtTime(msg,when);

而SendMessageAtTime(msg,when);方法最终的目的就是为了queue.enqueueMessage(msg, uptimeMillis);,其中msg为发送的Message对象,uptimeMillis为SystemClock.uptimeMillis() + when

查看系统的enqueueMessage方法,该方法最终实现在messageQueue当中,所有的message按执行的先后顺序,从小到大排列

final boolean enqueueMessage(Message msg, long when) {

            msg.when = when; // 将执行时间设置给msg.when
            Message p = mMessages;  // 定义变量p = mMessage  ,mMessage初终指向对列的第一个Message 对象

            if (p == null || when == 0 || when < p.when) {
				// 当队列中为空的时候,mMessage = msg
                msg.next = p;
                mMessages = msg;
                this.notify();
            } else {
				// 否则将要进入队列的msg的执行时间和队列中的message的执行时间进行比较,
				// 最终会使messageQueue中的所有的message按时间为顺序从小到大排列
				// 即按执行的先后顺序排列
                Message prev = null;
                while (p != null && p.when <= when) {
                    prev = p;
                    p = p.next;
                }
                msg.next = prev.next;
                prev.next = msg;
                this.notify();
            }
        }

消息发送成功这时候该调用Looper.loop方法:即完成了从MessageQueue中取出需要执行的Message,并执行我们重写的handlMessage方法

 public static final void loop() {
	//获得当前线程的looper对象及messageQueue对象
        Looper me = myLooper();
        MessageQueue queue = me.mQueue;

	//开启while(true)循环
        while (true) {
	    //从消息队列中取出一个message,如果message执行时间不到,那就wait等一会
            Message msg = queue.next(); // might block

	    //执行message 对应的handler中的dispatchMessage方法,即,执行我们重写的handleMessage方法
             msg.target.dispatchMessage(msg);

            }
        }
    }
时间: 2024-12-15 01:53:12

Handler消息机制源码分析的相关文章

Android Handler消息机制源码解析

好记性不如烂笔头,今天来分析一下Handler的源码实现 Handler机制是Android系统的基础,是多线程之间切换的基础.下面我们分析一下Handler的源码实现. Handler消息机制有4个类合作完成,分别是Handler,MessageQueue,Looper,Message Handler : 获取消息,发送消息,以及处理消息的类 MessageQueue:消息队列,先进先出 Looper : 消息的循环和分发 Message : 消息实体类,分发消息和处理消息的就是这个类 主要工

Handler消息机制 源码解读

基本概念 Handler消息机制的作用 大家知道子线程没有办法对UI界面上的内容进行操作,如果操作,将抛出异常:CalledFromWrongThreadException,为了让子线程能间接操作UI界面,Android中引入了Handler消息传递机制,通过Handler切换到主线程进行UI操作. Handler.Looper.MessageQueue.Message的关系是什么? Handler用于发送和处理消息.而发出的Message经过一系列的周转后,最终会传递回Handler中,最后更

拨云见日---android异步消息机制源码分析

做过windows GUI的同学应该清楚,一般的GUI操作都是基于消息机制的,应用程序维护一个消息队列,开发人员编写对应事件的回调函数就能实现我们想要的操作 其实android系统也和windows GUI一样,也是基于消息机制,今天让我们通过源码来揭开android消息机制的神秘面纱 谈起异步消息,就不能不提及Handler,在安卓中,由于主线程中不能做耗时操作,所以耗时操作必须让子线程执行,而且只能在主线程(即UI线程)中执行UI更新操作,通过Handler发送异步消息,我们就能更新UI,一

[Android]简略的Android消息机制源码分析

相关源码 framework/base/core/java/andorid/os/Handler.java framework/base/core/java/andorid/os/Looper.java framework/base/core/java/andorid/os/Message.java framework/base/core/java/andorid/os/MessageQueue.java libcore/luni/src/main/java/java/lang/ThreadLo

Android消息机制源码分析

本篇主要介绍Android中的消息机制,即Looper.Handler是如何协同工作的: Looper:主要用来管理当前线程的消息队列,每个线程只能有一个Looper Handler:用来将消息(Message)插入到当前线程的消息队列,并负责分发Looper中的消息,将消息发送到当前线程执行 具体关系图如下所示: 接下来我们来分析一下Looper和Handler的源码,了解一下其中的奥妙. 首先我们从一个程序运行的入口来分析,源码如下: public static void main(Stri

Android -- 消息处理机制源码分析(Looper,Handler,Message)

android的消息处理有三个核心类:Looper,Handler和Message.其实还有一个Message Queue(消息队列),但是MQ被封装到Looper里面了,我们不会直接与MQ打交道,因此我没将其作为核心类.下面一一介绍: Looper Looper的字面意思是“循环者”,它被设计用来使一个普通线程变成Looper线程.所谓Looper线程就是循环工作的线程.在程序开发中(尤其是GUI开发中),我们经常会需要一个线程不断循环,一旦有新任务则执行,执行完继续等待下一个任务,这就是Lo

Spark资源调度机制源码分析--基于spreadOutApps及非spreadOutApps两种资源调度算法

Spark资源调度机制源码分析--基于spreadOutApps及非spreadOutApps两种资源调度算法 1.spreadOutApp尽量平均分配到每个executor上: 2.非spreadOutApp尽量在使用单个executor的资源. 源码分析 org.apache.spark.deploy.master.Master 1.首先判断,master状态不是ALIVE的话,直接返回2.调度driver3. Application的调度机制(核心之核心,重中之重) 源码如下: 1 /*

Android 中View的绘制机制源码分析 三

到目前为止,measure过程已经讲解完了,今天开始我们就来学习layout过程,不过在学习layout过程之前,大家有没有发现我换了编辑器,哈哈,终于下定决心从Html编辑器切换为markdown编辑器,这里之所以使用"下定决心"这个词,是因为毕竟Html编辑器使用好几年了,很多习惯都已经养成了,要改变多年的习惯确实不易,相信这也是还有很多人坚持使用Html编辑器的原因.这也反应了一个现象,当人对某一事物非常熟悉时,一旦出现了新的事物想取代老的事物时,人们都有一种抵触的情绪,做技术的

Java NIO——Selector机制源码分析---转

一直不明白pipe是如何唤醒selector的,所以又去看了jdk的源码(openjdk下载),整理了如下: 以Java nio自带demo : OperationServer.java   OperationClient.java(见附件) 其中server端的核心代码: public void initSelector() { try { selector = SelectorProvider.provider().openSelector(); this.serverChannel1 =