Handler消息机制源码分析 -电脑资料

电脑资料 时间:2019-01-01 我要投稿
【www.unjs.com - 电脑资料】

   

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);            }        }    }

最新文章