码迷,mamicode.com
首页 > 其他好文 > 详细

Handler消息机制源码分析

时间:2014-10-18 17:03:47      阅读:178      评论:0      收藏:0      [点我收藏+]

标签:android   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);

            }
        }
    }





















Handler消息机制源码分析

标签:android   handler   

原文地址:http://blog.csdn.net/wanghed/article/details/40211577

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!