介绍handler之前首先我们来看下ThreadLocal类的用法
private static ThreadLocal<String> sthread;
public static void main(String[] args) {
sthread = new ThreadLocal<>();
sthread.set("这是我的第一个项目");
show();
new Thread(new Runnable() {
@Override
public void run() {
show();
}
});
}
public static void show(){
System.out.println(sthread.get());
}
ThreadLocal就是相当于是一个map集合,他的键就是当前的线程,值就是自己设置的值,如果ThreadLocal在主线程中set了值,在子线程中是没法获得的,这就是ThreadLocal的一个重要特点,可以将数据和当前线程绑定。
当我们应用开启的时候系统会调用他的ActivityThread类的Loop.PrepareXXX方法,然后这个方法会调用Loop.prepare()方法。
在这个方法里面我们把ThreadLocal类的对象所谓Loop的一个成员变量记录下来,这样有个好处在于下文handler。或者调用loop.loop()的时候很快的通过ThreadLocal获取到当前的looper对象。进而获得MessageQueen。
public final class Looper {
private static final String TAG = "Looper";
// sThreadLocal.get() will return null unless you've called prepare().
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
private static Looper sMainLooper; // guarded by Looper.class
final MessageQueue mQueue;
final Thread mThread;
volatile boolean mRun;
private Printer mLogging;
上面的方法同时是将looper对象绑定到当前线程上面(为下面的handler的时候回调用sThreadlocal.get()获得looper)
同时这个方法还把当前looper类的对象与相前线程绑定一起
其实内部就是系统在创建looper对象的prepare()方法的时候同时创建消息队列MessageQueen,然后把looper对象与当前线程绑定在一起
查看Handler源码可知
创建Handler对象的时候我们
public Handler() {
this(null, false);
}
然后调用到了
public Handler(Callback callback, boolean async) {
if (FIND_POTENTIAL_LEAKS) {
final Class<? extends Handler> klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
(klass.getModifiers() & Modifier.STATIC) == 0) {
Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
klass.getCanonicalName());
}
}
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
你看这个机制多好,首先系统自动的在主线程中创建了looper对象,调用了prepare()方法创建了消息队列,然后当handler对象一创建的时候调用构造函数,通过ThreadLocal的get()方法获得当前线程在ThreadLocal中设置的looper引用,然后通过looper对象的引用获得MessageQueen消息队列。当Handler对象获得了消息队列的引用的时候,
hanlder.sendMessage(msg)底层源码可知
*/
public final boolean sendMessage(Message msg)
{
return sendMessageDelayed(msg, 0);
}
然后调用了
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
然后调用了
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;//因为当前的是handler对象获得了looper引用,进而获得了MessageQueen对象的引用,自然能执行这个方法
if (queue == null) {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
return enqueueMessage(queue, msg, uptimeMillis);
}
再然后
注意这里面还有一个注意点就是msg.target=this,也就是将当前的Handler对象引用赋给msg的target属性、
下面我们看看looper.loop()方法执行了什么?
接着追了myLooper()
for (;;) {//死循环,会不会把主线程卡死???
不会被卡死。
涉及到Linux下的通讯机制,管道通讯的概念,管道就是内存中的一个特殊的一个文件,这个文件有两个句柄(其实就是java中的引用),一个是读的引用,一个是写的引用,当写的一端写入内容时,读的一端就会被唤醒,读的一端在没有读到消息时会休眠
总结looper.loop()做了什么?
其实就是首先通过myLooper()方法获得looper对象引用,然后通过looper对象的引用获得消息队列的引用,然后通过一个死循环不断地从消息队列中获取到消息,通过msg.this获得handler,然后调用handler对象的disPatchmessage()方法执行handMessage()【由我们外部重写】,这也就消息就循环执行起来了。。。
其实作为一个对技术热爱的程序员我们不可能仅仅停留在这里,试问假如主线程给子线程发消息那我们该如何去做?
由于安卓的主线程比较特殊在应用被开启的时候就会调用Looper.prepare()方法创建了Looper.MessageQueen,那我们我们子线程如果也想实现主线程给其发消息,那也得手动创建Looper对象,进而获取到MessageQueen队列,然后不断地往里面发消息。然后通过一个Looper.loop()方法不断地从里面取消息,但是这里有个弊端就是由于Looper.loop()会堵塞住子线程导致子线程没法结束,所以一般这种方式仅仅用于测试,很少这么去用。
public class MainActivity extends Activity {
private Handler subHandler;
//1
private Handler mainHandler = new Handler(){
//2
@Override
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case 1:
Toast.makeText(MainActivity.this, msg.toString(), Toast.LENGTH_SHORT).show();
break;
default:
break;
}
};
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//创建一个子线程
Thread subThread = new Thread(new Runnable() {
@Override
public void run() {
//(1)
Looper.prepare();
//(2)
subHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
Toast.makeText(MainActivity.this, msg.toString(), Toast.LENGTH_LONG).show();
}
};
Log.d("tag", "我是loop前面的代码");
//(3)
Looper.loop();//死循环,这样子线程就一直存在
Log.d("tag", "我是loop后面的代码");
}
});
subThread.start();
}
//开启子线程,模拟耗时任务
public void start(View view){
new Thread(new Runnable() {
@Override
public void run() {
//模拟耗时操作
SystemClock.sleep(5000);
Message msg = new Message();
msg.obj = Thread.currentThread().getName();
msg.what = 1;
//3
mainHandler.sendMessage(msg);
}
}).start();
}
//主线程给子线程发送消息
public void send2SubThread(View view){
//发送消息
subHandler.obtainMessage(2, "我是主线程给你发送的数据").sendToTarget();
}
}