Android学习笔记(十四) Handler理论补充
一、如何下载Android源码
在SDK Manager中选中Sources for Android SDK。
二、ThreadLocal初步介绍
1)执行ThreadLocal对象(static final ThreadLocal sThreadLocal)的set(Object obj)方法,将会向存入一个以当前线程为键的键值对。
2)执行ThreadLocal对象的get()方法,将会根据当前线程对象为键,取出与之对应的值。
在之前提到的Looper方法调用中:
执行Looper.prepare时,系统会生成一个Looper对象,然后和当前线程通过ThreadLocal存储(set)起来。生成Handler对象时,又根据线程名将Looper对象取(get)出来,然后赋值给Handler对象的mLooper成员变量。因此Looper和Handler的关系是通过ThreadLocal联系起来的。
生成Looper对象时会生成一个与之相对应的MessageQueue对象。之后生成Handler对象时,将Looper对象和MessageQueue对象都赋值给Looper的成员变量。
三、什么是Message对象的target变量
实际上是生成Message对象时使用的Handler对象。
一个Handler对应一个Looper对象,一个Looper对象对应一个MessageQueue对象,使用Handler生成Message,所生成Message对象的target属性,就是该Handler对象(发送Message的Handler对象)。
四、Handler的post(Runnable)方法
class TestThread extends Thread{ @Override public void run(){ Runnable r = new Runnable(){ @Override public void run(){ String currentThreadName = Thread.currentThread().getName(); System.out.print("当前线程的名称是:"+currentThreadName); } }; handler.post(r); //将Runnable对象放到MessageQueue里。 //在主线程中生成Handler对象,然后取出r对象。 //打印出来的结果是“当前线程的名称是:main” } }
这里有两个问题:
1)如何将Runnable对象放在MessageQueue里?
2)Looper对象(主线程)从消息队列中取出了r对象之后做了些什么?
第一个问题:
将Runnable对象放到MessageQueue里,实际上是生成了一个Message对象,并将r赋值给Message对象的callBack属性,然后再将Message对象放在消息队列中。
第二个问题:
Looper对象(主线程)从消息队列当中取出了r对象(根据第一问,此处应是携带r的Message对象)。我们可以猜测,取出r对象后-->Thread t = new Thread(r)-->t.start()。但是根据结果可以看出,该猜测错误。
正确情况是:取出Message对象之后调用了dispatchMessage()方法,然后判断Message的callback属性是否为空。此时callBack属性有值,所以执行了handleCallback(Message msg),在该方法中直接执行了msg.callback.run()。
注意:直接执行run()方法时,不会开辟一个新线程,而是直接执行run()里面的内容。(这在(四)区分start()和run()中提到过)。
所以在run()方法里可以写上更改UI的代码。